Skip to content

Instantly share code, notes, and snippets.

@aquiseb
Last active February 15, 2020 21:26
Show Gist options
  • Select an option

  • Save aquiseb/2c50759aae0694dc1ff1f512f1f4dc0d to your computer and use it in GitHub Desktop.

Select an option

Save aquiseb/2c50759aae0694dc1ff1f512f1f4dc0d to your computer and use it in GitHub Desktop.
minimal-graphql-serverless

Minimal Graphql Serverless

Shows how to use graph-gophers/graphql-go in a serverless environment and how to test it with ginkgo.

Comes from this post but was adjusted to use ginkgo.

Run test with

ginkgo -v
package main_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestHelloGraphql(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "HelloGraphql Suite")
}
package main
import (
"context"
"encoding/json"
"errors"
"log"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
graphql "github.com/graph-gophers/graphql-go"
)
// https://medium.com/a-man-with-no-server/building-a-golang-graphql-api-on-aws-lambda-b5278b7afc8c
// Schema : GraphQL schema definition. This is an example schema
var Schema = `
schema {
query: Query
}
type Person{
id: ID!
firstname: String!
lastname: String
}
type Query{
person(id: ID!): Person
}
`
type person struct {
ID graphql.ID
Firstname string
Lastname string
}
var people = []*person{
{
ID: "1000",
Firstname: "Bob",
Lastname: "Dylan",
},
{
ID: "1001",
Firstname: "John",
Lastname: "Doe",
},
}
type personResolver struct {
p *person
}
func (r *personResolver) ID() graphql.ID {
return r.p.ID
}
func (r *personResolver) Firstname() string {
return r.p.Firstname
}
func (r *personResolver) Lastname() *string {
return &r.p.Lastname
}
// Resolver : Struct with all the resolver functions
type resolver struct{}
// Person : Resolver function for the "Person" query
func (r *resolver) Person(args struct{ ID graphql.ID }) *personResolver {
if p := peopleData[args.ID]; p != nil {
return &personResolver{p}
}
return nil
}
var peopleData = make(map[graphql.ID]*person)
var mainSchema *graphql.Schema
var (
// ErrNameNotProvided is thrown when a name is not provided
QueryNameNotProvided = errors.New("no query was provided in the HTTP body")
)
func Handler(context context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
log.Printf("Processing Lambda request %s\n", request.RequestContext.RequestID)
// If no query is provided in the HTTP request body, throw an error
if len(request.Body) < 1 {
return events.APIGatewayProxyResponse{}, QueryNameNotProvided
}
var params struct {
Query string `json:"query"`
OperationName string `json:"operationName"`
Variables map[string]interface{} `json:"variables"`
}
if err := json.Unmarshal([]byte(request.Body), &params); err != nil {
log.Print("Could not decode body", err)
}
response := mainSchema.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,
}, nil
}
func init() {
for _, p := range people {
peopleData[p.ID] = p
}
mainSchema = graphql.MustParseSchema(Schema, &resolver{})
}
func main() {
lambda.Start(Handler)
}
package main_test
import (
"net/http"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
main "github.com/astenmies/stratifio-api/_functions/hello-graphql" // replace with your package
"context"
"github.com/aws/aws-lambda-go/events"
)
var _ = Describe("hello-graphql main test", func() {
ctx := context.TODO()
tests := []struct {
it string
request events.APIGatewayProxyRequest
expect string
context context.Context
err error
}{
{
it: "[PERSON] get person with id",
// Test that the handler responds with the correct response
// when a valid name is provided in the HTTP body
request: events.APIGatewayProxyRequest{
Body: `{"query":"query test {\n person(id:\"1000\") {\n id\n firstname\n }\n}\n","variables":null,"operationName":"test"}`,
},
expect: "{\"data\":{\"person\":{\"id\":\"1000\",\"firstname\":\"Bob\"}}}",
context: ctx,
err: nil,
},
}
Context("multiple queries", func() {
for _, test := range tests {
response, _ := main.Handler(test.context, test.request)
It(test.it, func() {
// Expect(err).To(Equal(test.err))
Expect(response.Body).To(Equal(test.expect))
Expect(response.StatusCode).To(Equal(http.StatusOK))
})
}
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment