A command-line application and utility package that helps you build web backend services with Go and PostgreSQL (previously known as EcoSystem).
I tend to write backends with a very thick database layer (PostgreSQL) and a very thin application (Go) layer. Rather than recreate brittle functionality in application code, I prefer to take advantage of the power of Postgres, with its roles, permissions, grants, views, row-level security, functions and triggers. I keep my business and data-control logic right in the database and totally avoid application level ORMs and suchlike.
This leads naturally to mostly generic application code, of the CRUDy, boilerplate type. In fact, this approach leads to application code that is so generic that you could, in theory, avoid writing any at all. The excellent projects PostgREST and PostGraphQL take the same approach and give you a REST API and/or GraphQL API respectively, without the need to touch any application code. I strongly recommend taking a look at those projects to see if they fulfill your requirements.
Ghost shares a common philosophy with the above projects - indeed Ghost has a generic 'PostgreSQL-to-REST' subpackage available should you need it. If you like this database-first approach, but need to write your own, custom server, then Ghost could help you reduce:
- Repetitive tasks
- Boilerplate code
- Reimplementing generic functionality
Ghost is both a command-line utility and a Go package that you can import into your program.
The command-line utility helps with mundane tasks like generating configuration files, installing SQL code into the database, creating users and so on.
The Go package (which the command-line utility is built on) gives you quick access to all the low-level utilities necessary for getting your Go/Postgres service off the ground, like configuration, database connection, routing, middleware, email etc.
In the future, Ghost will be extended with handy sub-packages. At the moment, we have auth
, which gives you utilites, handlers and even routes, all for dealing with authentication. You can use the basic utilities only, use the handlers in your own routes, or just take the routes as they come, hook them into the central router and fire up. All future Ghost pakages will work that way.
You should have Go (> 1.7) already installed and your $GOPATH correctly configured. You should also have a PostgreSQL server somewhere that you can access - easiest for development would be to have one on localhost:5432.
-
Fetch the source code and dependencies and compile into an executable which will go into your $GOPATH/bin directory. That's just
go get github.com/jpincas/ghost
. Assuming your $GOPATH/bin is part of your PATH, you should now be able to run 'ghost' from anywhere on the command line. -
Log into your Postgres server and create a new database. Call it testdb - that way you won't have to make any changes to the default database configuration.
-
Make a new folder
myghostapp
in your Go path andcd
into it:
-
Just type
ghost
to get going. This will give you a defaultconfig.json
-
If you're working locally, the defaults will probably just work out-of-the-box. Otherwise, open config.json and edit the database connection parameters.
-
Ghost needs to create a number of built-in tables, roles, permissions and functions, as well as a few folders, so just type
ghost init
to have it do that for you. -
Set yourself up as an admin user with full permissions by typing
ghost new user [[email protected]] --admin
. -
Create a new 'bundle' (more on those later) by entering
ghost new bundle mybundle
. -
In mybundle/install/00_install.sql, paste this SQL to create a table:
CREATE TABLE helloworld(
hello text);
- In mybundle/demodata/00_demodata.sql, paste this SQL to add a new row:
INSERT INTO helloworld(hello)
VALUES ('world');
- Install your new bundle and demo data with
ghost install mybundle --demodata
- Create
main.go
and copy this short program:
package main
import (
"fmt"
"net/http"
"os"
"github.com/jpincas/ghost/ghost"
)
func main() {
//Hook into Ghost's BeforeServe' callback
//Add our custom route 'hello' which triggers the 'helloWorld' handler
ghost.BeforeServe = func() {
ghost.App.Router.Get("/hello", helloWorld)
}
//Run Ghost's 'Serve' command to start the server
if err := ghost.ServeCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
//our helloWorld handler
func helloWorld(w http.ResponseWriter, r *http.Request) {
var json string //to hold our db result
//Use Ghost's convenience functions to build a simple SQL query
// We ask for all fields from table 'helloworld'
// executing the query as 'admin' and returning JSON from Postgres
sql := ghost.SqlQuery(fmt.Sprintf(ghost.SQLToSelectAllFieldsFrom, "mybundle", "helloworld")).RequestSingleResultAsJSONObject().SetQueryRole("admin").ToSQLString()
ghost.App.DB.QueryRow(sql).Scan(&json)
w.Write([]byte(json))
return
}
-
Build with
go build
and then run in 'debug' mode with./myghostapp -s=secret -b
-
Visit localhost:3000/hello with your browser and get the response
{"hello":"world"}
. Notice how Ghost logs the SQL query executed since we ran it in debug mode.