Start by initializing a go module.

go mod init github.com/<profile>/<repo-name>

Now, let’s create our graphql microservice at ./cmd/graphql/main.go. For now, lets just add a main func and log a hello world

package graphql import "fmt" func main() {

fmt.Println("Hello World")

}

Word, now we are cooking. Lets add our handler function. Create it at ./internal/pkg/handler/graphql.go.

package handler import (

"context"

"encoding/json"

"errors"

"log"

"github.com/aws/aws-lambda-go/events"

"github.com/graph-gophers/graphql-go"

) // GraphQl graphql handler

type GraphQl struct {

Schema *graphql.Schema

} // BuildSchema builds schema

func (g *GraphQl) BuildSchema(schema string, resolver interface{}) {

opts := []graphql.SchemaOpt{graphql.UseFieldResolvers()}

g.Schema = graphql.MustParseSchema(schema, resolver, opts...)

} var (

// ErrQueryNameNotProvided is thrown when a name is not provided

ErrQueryNameNotProvided = errors.New("no query was provided in the HTTP body")

) // Lambda is the Lambda function handler

func (g *GraphQl) Lambda(context context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {

log.Printf("Processing Lambda request %s

", request.RequestContext.RequestID) // If no query is provided in the HTTP request body, throw an error

if len(request.Body) < 1 {

return events.APIGatewayProxyResponse{}, ErrQueryNameNotProvided

} var params struct {

Query string `json:"query"`

OperationName string `json:"operationName"`

Variables map[string]interface{} `json:"variables"`

} if err := json.Unmarshal([]byte(request.Body), ¶ms); err != nil {

log.Print("Could not decode body", err)

} response := g.Schema.Exec(context, params.Query, params.OperationName, params.Variables)

responseJSON, err := json.Marshal(response) if err != nil {

log.Print("Could not decode body")

} return events.APIGatewayProxyResponse{

Body: string(responseJSON),

StatusCode: 200,

Headers: map[string]string{

"Access-Control-Allow-Origin": "*", // TODO use env var

"Access-Control-Allow-Methods": "POST, GET, OPTIONS",

"Access-Control-Allow-Headers": "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization",

},

}, nil

}

You may have to run a go get command to install the dependencies if your IDE isn’t set up to install them automatically. I recommend VSCode with the Go extension. Now lets update our main file to use the handler:

var graphql = new(handler.GraphQl) func main() {

lambda.Start(graphql.Lambda)

}

Update your imports here as well. So now we need to put on our devops hat, and utilize some of those utilities we installed earlier. touch template.yaml will stub out our AWS SAM CLI template. Populate it with:

---

AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31 Resources:

LocalApi:

Type: AWS::Serverless::Api

Properties:

StageName: local

Cors:

AllowHeaders: "'Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization'"

AllowOrigin: "'*'"

AllowMethods: "'POST, GET, OPTIONS'" GraphqlFunction:

Type: AWS::Serverless::Function

Properties:

Handler: ./cmd/graphql/main

Runtime: go1.x

Events:

GetEvent:

Type: Api

Properties:

RestApiId: !Ref LocalApi

Path: /query

Method: post

Environment:

Variables:

DATABASE_USERNAME: postgres

DATABASE_PASSWORD: postgres

DATABASE_HOST: host.docker.internal

DATABASE_PORT: 5432

DATABASE: serverlessgraphqlgo

SSL_MODE: disable

If you haven’t already created a Makefile, please do so now. Please note, since our serverless function and fake API gateway will be deployed using the SAM CLI to a docker container that mirrors an AWS account, we will need to build our binary targeting linux architecture.

OUTPUT = ./cmd/graphql/main

.PHONY: clean

clean:

rm -f $(OUTPUT) .PHONY: install

install:

go get ./... graphql: ./cmd/graphql/main.go

go build -o $(OUTPUT) ./cmd/graphql/main.go # compile the code to run in Lambda (local or real)

.PHONY: lambda

lambda:

GOOS=linux GOARCH=amd64 $(MAKE) graphql .PHONY: build

build: clean lambda .PHONY: local

local: build

sam local start-api .PHONY: migrate-up

migrate-up:

migrate -path db/migrations -database postgres://postgres@localhost:5432/strutdb?sslmode=disable up .PHONY: migrate-down

migrate-down:

migrate -path db/migrations -database postgres://postgres@localhost:5432/strutdb?sslmode=disable down