Go, GraphQL, and Neo4j

Magbic Aleman
Mar 27, 2017 · 3 min read

Up until this weekend I’ve never used Go, never setup a GraphQL server, nor have taken advantage of Neo4j. I’m no genius, just hard headed and persistent.

I’m not an expert in Go, GraphQL, nor Neo4j, this was written in hopes to get you started on a track.

A little pep, Go’s a long way

I started with, researching how to setup a Go, microservice.

package mainimport (
“fmt”
“net/http”
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, “Welcome, %s!”, r.URL.Path[1:])
}
func main() {
http.HandleFunc(“/”, handler)
http.ListenAndServe(“:8080”, nil)
}

source: http://nordicapis.com/writing-microservices-in-go/

Cool beans, simple enough.

Let’s get contained with Docker

The next move was to start my stack with Docker. I started to looking up “Go microservices with docker”, and this lead me to this great Dockerfile.

My docker-compose.yml is as follows;

version: '2'
services:
graphql:
depends_on:
build: ./go/graphql-server
image: go/graphql
container_name: go-graphql
ports:
- "9000:8080"

My Dockerfile in ./go/graphql-server is as follows;

FROM golang:1.8# Install dependecies
# Coming SOON
# copy the local package file to the container workspace
ADD . /go/src/graphql-server
WORKDIR /go/src/graphql-serverRUN go install graphql-serverENTRYPOINT /go/bin/graphql-serverEXPOSE 8080

Using the code above (microservice example), resulted in great success.

Go GraphQL

Now it was time for the magic… let’s fast forward a bit here, because you might not care about my process;

Let’s see them files…

docker-compose.yml

version: '2'
services:
neo4j:
image: neo4j:latest
ports:
- "7474:7474"
- "7687:7687"
volumes:
- ./dbs/n4j/data:/data
graphql:
depends_on:
- neo4j
build: ./go/graphql-server
image: go/graphql
container_name: go-graphql
ports:
- "9000:8080"

As an FYI, if you start your Neo4j connection in Go in the main() file you’ll have a connection error, even if your graphql service depends_on: - neo4j. I don’t know any better.

Dockerfile

FROM golang:1.8# Install dependecies
RUN go get github.com/graphql-go/graphql
RUN go get github.com/graphql-go/handler
RUN go get github.com/mnmtanish/go-graphiql
RUN go get github.com/rs/cors
RUN go get github.com/johnnadratowski/golang-neo4j-bolt-driver
# copy the local package file to the container workspace
ADD . /go/src/graphql-server
WORKDIR /go/src/graphql-serverRUN go install graphql-serverENTRYPOINT /go/bin/graphql-serverEXPOSE 8080

main.go

package mainimport (
"log"
"net/http"
"github.com/rs/cors"
"github.com/graphql-go/graphql"
"github.com/graphql-go/handler"
"github.com/mnmtanish/go-graphiql"
driver "github.com/johnnadratowski/golang-neo4j-bolt-driver"
)
type Person struct {
ID int64 `json:"id"`
Name string `json:"name"`
From string `json:"from"`
}
// var People []Personfunc getPeople() []Person {
// Neo4j
db, err := driver.NewDriver().OpenNeo("bolt://neo4j:neo4j2@neo4j:7687")
if err != nil {
log.Println("error connecting to neo4j:", err)
}
defer db.Close()cypher := `
MATCH
(n:Person)
RETURN
ID(n) as id, n.name as name, n.from as from
LIMIT {limit}`
data, _, _, err := db.QueryNeoAll(cypher, map[string]interface {}{ "limit": 25})if err != nil {
log.Println("error querying person:", err)
// w.WriteHeader(500)
// w.Write([]byte("an error occured querying the DB"))
// return
} else if len(data) == 0 {
// w.WriteHeader(404)
// return
}
results := make([]Person, len(data))for idx, row := range data {
results[idx] =
Person{
ID: row[0].(int64),
Name: row[1].(string),
From: row[2].(string),
}
}
return results}var personType = graphql.NewObject(
graphql.ObjectConfig{
Name: "Person",
Fields: graphql.Fields {
"id" : &graphql.Field {
Type: graphql.Int,
},
"name": &graphql.Field {
Type: graphql.String,
},
"from": &graphql.Field {
Type: graphql.String,
},
},
},
)
var queryType = graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"People": &graphql.Field{
Type: graphql.NewList(personType),
Description: "List of people",
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
// People = getPeople()
return getPeople(), nil
},
},
},
})
var Schema, _ = graphql.NewSchema(graphql.SchemaConfig{
Query: queryType,
})
func main() {c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
})
h := handler.New(&handler.Config{
Schema: &Schema,
Pretty: true,
})
// serve HTTP
serveMux := http.NewServeMux()
// serveMux.HandleFunc("/neo", neo4jHandler)
serveMux.Handle("/graphql", c.Handler(h))
serveMux.HandleFunc("/graphiql", graphiql.ServeGraphiQL)
http.ListenAndServe(":8080", serveMux)
}

This is an unfinished example, no mutations and it’s all in one file. It’s probably some of the worst Go code someone has seen.

I really hopes this helps anyone wondering about this particular stack. Until next time, I’m wishing you the best.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade