Documentation ¶
Index ¶
Examples ¶
Constants ¶
const GinContextKey = "GinContext"
Key for setting `*gin.Context` value of the current request to the context
Variables ¶
var UploadType = graphql.NewScalar( graphql.ScalarConfig{ Name: "Upload", Description: "File upload scalar", Serialize: func(value interface{}) interface{} { return value }, }, )
GraphQL scalar to represent file upload variable
Functions ¶
func GetGinContext ¶
Extracts and returns the current `*gin.Context` value from the context `ctx`.
Types ¶
type ContextProviderFn ¶
Function to update or modify the context passed down to the resolver functions
type GraphQLApp ¶
type GraphQLApp struct { Schema graphql.Schema ContextProviders []ContextProviderFn }
GraphQL app structure
Example (Add_custom_headers) ¶
// Create schema schema, _ := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "header": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.ResolveParams) (interface{}, error) { c := GetGinContext(p.Context) c.Header("Custom-Header", "some-header-value") return "hello", nil }, }, }, }), }) // Create graphql app app := New(schema) // Create router router := gin.Default() // Add graphql handler router.POST("/graphql", app.Handler()) // Run server // router.Run() // Sample output capture req, _ := http.NewRequest( "POST", "/graphql", bytes.NewBuffer( []byte(`{"query": "query { header }", "operationName": "", "variables": {}}`), ), ) req.Header.Add("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) headers := w.Header() body := string(w.Body.Bytes()) fmt.Println("Headers:") fmt.Println(headers) fmt.Println("Body:") fmt.Println(body)
Output: Headers: map[Content-Type:[application/json; charset=utf-8] Custom-Header:[some-header-value]] Body: {"data":{"header":"hello"}}
Example (Context_usage) ¶
// Your example database userStore := []map[string]interface{}{ { "name": "John", "email": "a@b.c", }, { "name": "Kratos", "email": "c@b.a", }, } // Create schema schema, _ := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "users": &graphql.Field{ Type: graphql.NewList(graphql.NewObject(graphql.ObjectConfig{ Name: "User", Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, }, "email": &graphql.Field{ Type: graphql.String, }, }, })), Resolve: func(p graphql.ResolveParams) (interface{}, error) { // retrieve the store/database from the context users := p.Context.Value("userStore").([]map[string]interface{}) // use it as you want return users, nil }, }, }, }), }) // Create graphql app // You can add your context provider here or when attaching the handler to a route app := New(schema, func(c *gin.Context, ctx context.Context) context.Context { return context.WithValue(ctx, "userStore", userStore) }) // Create router router := gin.Default() // Add handler router.POST("/graphql", app.Handler()) // You could add your context providers here too // router.POST("/graphql", app.Handler(func(c *gin.Context, ctx context.Context) context.Context { // return context.WithValue(ctx, "userStore", userStore) // })) // Run server // router.Run() // Sample output capture req, _ := http.NewRequest( "POST", "/graphql", bytes.NewBuffer( []byte( `{"query": "query { users { name email } }", "operationName": "", "variables": {}}`, ), ), ) req.Header.Add("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) body := string(w.Body.Bytes()) fmt.Println(body)
Output: {"data":{"users":[{"email":"a@b.c","name":"John"},{"email":"c@b.a","name":"Kratos"}]}}
Example (Multiple_file_upload) ¶
// create your own json representation of the uploaded file uploadInfoType := graphql.NewObject(graphql.ObjectConfig{ Name: "UploadInfo", Fields: graphql.Fields{ "filename": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.ResolveParams) (interface{}, error) { file := p.Source.(*multipart.FileHeader) return file.Filename, nil }, }, "size": &graphql.Field{ Type: graphql.Int, Resolve: func(p graphql.ResolveParams) (interface{}, error) { file := p.Source.(*multipart.FileHeader) return file.Size, nil }, }, }, }) // Construct graphql schema schema, _ := graphql.NewSchema(graphql.SchemaConfig{ // just a dummy query, have to include a query with at least one field Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "hello": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return "world", nil }, }, }, }), Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ "uploadFiles": &graphql.Field{ // use graphqlgin.UploadType like this for file upload scalar Args: graphql.FieldConfigArgument{ "files": &graphql.ArgumentConfig{ Type: graphql.NewList(UploadType), }, }, // use your own type to respond Type: graphql.NewList(uploadInfoType), // handle the uploaded file anyway you want Resolve: func(p graphql.ResolveParams) (interface{}, error) { return p.Args["files"], nil }, }, }, }), }) // Create graphql app app := New(schema) // Create router router := gin.Default() // Add graphql handler to the router router.POST("/graphql", app.Handler()) // Run graphql server // router.Run() // Sample output capturing buffer := bytes.NewBuffer(nil) form := multipart.NewWriter(buffer) form.WriteField( "operations", `{"query": "mutation ($files: [Upload!]!) { uploadFiles(files: $files) { filename size } }", "operationName": "", "variables": { "files": [null, null] } }`, ) form.WriteField( "map", `{"0": ["variables.files.0"], "1": ["variables.files.1"]}`, ) w, _ := form.CreateFormFile("0", "hello.txt") w.Write([]byte("Hello, World")) w2, _ := form.CreateFormFile("1", "bingo.txt") w2.Write([]byte("Bingo")) form.Close() req, _ := http.NewRequest("POST", "/graphql", buffer) req.Header.Add("Content-Type", form.FormDataContentType()) rec := httptest.NewRecorder() router.ServeHTTP(rec, req) body := rec.Body.Bytes() fmt.Println(string(body))
Output: {"data":{"uploadFiles":[{"filename":"hello.txt","size":12},{"filename":"bingo.txt","size":5}]}}
Example (Simple_usage) ¶
// Construct graphql schema schema, _ := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "hello": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return "world", nil }, }, }, }), }) // Create graphql app instance app := New(schema) // Create gin router router := gin.Default() // Add graphql handler to the router router.POST("/graphql", app.Handler()) // Run app server // router.Run() // Example capturing of output req, _ := http.NewRequest( "POST", "/graphql", bytes.NewBuffer([]byte( `{"query": "query Hello { hello }", "operationName": "Hello", "variables": {}}`, ))) req.Header.Add("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) data := w.Body.Bytes() fmt.Println(string(data))
Output: {"data":{"hello":"world"}}
Example (Single_file_upload) ¶
// create your own json representation of the uploaded file uploadInfoType := graphql.NewObject(graphql.ObjectConfig{ Name: "UploadInfo", Fields: graphql.Fields{ "filename": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.ResolveParams) (interface{}, error) { file := p.Source.(*multipart.FileHeader) return file.Filename, nil }, }, "size": &graphql.Field{ Type: graphql.Int, Resolve: func(p graphql.ResolveParams) (interface{}, error) { file := p.Source.(*multipart.FileHeader) return file.Size, nil }, }, }, }) // Construct graphql schema schema, _ := graphql.NewSchema(graphql.SchemaConfig{ // just a dummy query, have to include a query with at least one field Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "hello": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.ResolveParams) (interface{}, error) { return "world", nil }, }, }, }), Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ "uploadFile": &graphql.Field{ // use graphqlgin.UploadType like this for file upload scalar Args: graphql.FieldConfigArgument{ "file": &graphql.ArgumentConfig{ Type: UploadType, }, }, // use your own type to respond Type: uploadInfoType, // handle the uploaded file anyway you want Resolve: func(p graphql.ResolveParams) (interface{}, error) { return p.Args["file"], nil }, }, }, }), }) // Create graphql app app := New(schema) // Create router router := gin.Default() // Add graphql handler to the router router.POST("/graphql", app.Handler()) // Run graphql server // router.Run() // Sample output capturing buffer := bytes.NewBuffer(nil) form := multipart.NewWriter(buffer) form.WriteField( "operations", `{"query": "mutation UploadFile ($file: Upload!) { uploadFile(file: $file) { filename size } }", "operationName": "UploadFile", "variables": { "file": null } }`, ) form.WriteField( "map", `{"file": ["variables.file"]}`, ) w, _ := form.CreateFormFile("file", "hello.txt") w.Write([]byte("Hello, World")) form.Close() req, _ := http.NewRequest("POST", "/graphql", buffer) req.Header.Add("Content-Type", form.FormDataContentType()) rec := httptest.NewRecorder() router.ServeHTTP(rec, req) body := rec.Body.Bytes() fmt.Println(string(body))
Output: {"data":{"uploadFile":{"filename":"hello.txt","size":12}}}
func New ¶
func New(schema graphql.Schema, contextProviders ...ContextProviderFn) *GraphQLApp
Constructs a new GraphQL app
func (*GraphQLApp) Handler ¶
func (app *GraphQLApp) Handler(contextProviders ...ContextProviderFn) gin.HandlerFunc
Factory function to create `gin.HandlerFunc` for the GraphQL application.
Each `contextProviders` will be called before running `graphql.Do` to generate/construct the context, and this context will be passed down to the resolver by `graphql.Do` function. Any context provider added before or with this function will be executed sequentially for each request.
type GraphQLRequest ¶
type GraphQLRequest struct { GraphQLRequestParams OperationsString string `json:"-" form:"operations"` MapString string `json:"-" form:"map"` }
GraphQL request parameters including file upload maps and operations
type GraphQLRequestParams ¶
type GraphQLRequestParams struct { RequestString string `json:"query" form:"query"` VariableValues map[string]interface{} `json:"variables" form:"variables"` OperationName string `json:"operationName" form:"operationName"` }
Basic GraphQL request parameters