GraphQL

GraphQL is both a query language for the API and a runtime for your data queries. GraphQL provides an easy-to-understand set of complete descriptions of the data in your API, enabling a client to get exactly what it needs without any redundancy, making it easier for the API to evolve over time, and for building powerful developer tools.

In server-side development based on Node, GraphQL technology is relatively mature and commonly used. As a high-performance modern language, Golang also has a high usage rate in Web server development.

Graphql-go is a GraphQL implementation of Go/Golang. The library also encapsulates graphQL-Go-Handler: middleware that processes GraphQL queries through HTTP requests.

package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/graphql-go/graphql"
)

func main(a) {
	// Schema
	fields := graphql.Fields{
		"hello": &graphql.Field{
			Type: graphql.String,
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return "world".nil
			},
		},
	}
	rootQuery := graphql.ObjectConfig{Name: "RootQuery", Fields: fields}
	schemaConfig := graphql.SchemaConfig{Query: graphql.NewObject(rootQuery)}
	schema, err := graphql.NewSchema(schemaConfig)
	iferr ! =nil {
		log.Fatalf("failed to create new schema, error: %v", err)
	}

	// Query
	query := ` { hello } `
	params := graphql.Params{Schema: schema, RequestString: query}
	r := graphql.Do(params)
	if len(r.Errors) > 0 {
		log.Fatalf("failed to execute graphql operation, errors: %+v", r.Errors)
	}
	rJSON, _ := json.Marshal(r)
	fmt.Printf("%s \n", rJSON) / / {" data ": {" hello", "world"}}
}
Copy the code

Let’s start

The go mod version recommends that any project created after 1.12 should have a go. Mod to manage dependencies.

According to the above example, when using, you need to have Schema and Query to parse and generate Query document objects, and then use the Query to parse the Query document objects.

The first step

SDL syntax is generally recommended. Graphql files, stronger type requirements need to write code like the following.

// schemaQuery Queries function routes
var schemaQuery= graphql.NewObject(graphql.ObjectConfig{
	Name:        graphql.DirectiveLocationQuery,
	Description: "Query function",
	Fields: graphql.Fields{
		// Simply output a string
		"hello": &graphql.Field{
			Type:        graphql.String, // Return type
			Description: "Output world".// Explain the explanation
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				// Return the corresponding type of data value according to the query handler method
				return "word".nil}},// Output parameters directly
		"echo": &graphql.Field{
			Type:        graphql.String, // Return type
			Description: "Direct output of parameters".// Explain the explanation
			Args: graphql.FieldConfigArgument{ // Parameters receive
				"toEcho": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),  // Receive parameter type, representing a non-empty string
				},
			},
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				// Return the corresponding type of data value according to the query handler method
				return p.Args["toEcho"]. (string), nil}},}})Copy the code

The second step

Compose Schema documents

// Schema
var Schema graphql.Schema
Schema, _ = graphql.NewSchema(graphql.SchemaConfig{
	Query:    schemaQuery, // Query the function Schema
	Mutation: schemaMutation, // If there is a commit function Schema
})
Copy the code

The third step

Get parameters and execute the query function corresponding to the Schema

// ExecuteQuery GraphQL
func ExecuteQuery(params *graphql.Params) *graphql.Result {
	params.Schema = schema
	return graphql.Do(*params)
}
Copy the code

The fourth step

Parses the parameters in the route entry and uses the query

// Request entry
http.HandleFunc("/graphql".func(res http.ResponseWriter, req *http.Request) {
	// Output in JSON format, status 200
	res.Header().Add("Content-Type"."application/json; charset=utf-8")
	res.WriteHeader(http.StatusOK)
	// Query, Variables, OperationName
	opts := ParseRequestOptions(req)  // We need to write our own function to get the parameters
	// Run graphQL Query Query
	result := ExecuteQuery(&graphql.Params{  // Use the query
		RequestString:  opts.Query,
		VariableValues: opts.Variables,
		OperationName:  opts.OperationName,
		Context:        req.Context(),
	})
	// Error output
	if len(result.Errors) > 0 {
		log.Printf("errors: %v", result.Errors)
	}
	// map to JSON serialization
	buff, _ := json.Marshal(result)
	_, _ = res.Write(buff)
})
Copy the code

Basically through the above four steps, simple use of GraphQL interface operation.

Query selection field

Graphql-compliant design is based on the corresponding query field of the corresponding field information, not query all fields according to the field return. The SQL field query should be performed after the field in the query is obtained. Getting the fields of the submitted query is a bit of a chore.

Based on the summary of most issues, the following two methods are provided for function analytic acquisition.

// SelectionFieldNames query selection fields
func SelectionFieldNames(fieldASTs []*ast.Field) []string{
	fieldNames := make([]string.0)
	for _, field := range fieldASTs {
		selections := field.SelectionSet.Selections
		for _, selection := range selections {
			fieldNames = append(fieldNames, selection.(*ast.Field).Name.Value)
		}
	}
	return fieldNames
}

/ / selectedFieldsFromSelections submitted to query the list of fields
func selectedFieldsFromSelections(params graphql.ResolveParams, selections []ast.Selection) (selected map[string]interface{}, err error) {
	selected = map[string]interface{} {}for _, s := range selections {
		switch s := s.(type) {
		case *ast.Field:
			if s.SelectionSet == nil {
				selected[s.Name.Value] = true
			} else {
				selected[s.Name.Value], err = selectedFieldsFromSelections(params, s.SelectionSet.Selections)
				iferr ! =nil {
					return}}case *ast.FragmentSpread:
			n := s.Name.Value
			frag, ok := params.Info.Fragments[n]
			if! ok { err = fmt.Errorf("getSelectedFields: no fragment found with name %v", n)
				return
			}
			selected[s.Name.Value], err = selectedFieldsFromSelections(params, frag.GetSelectionSet().Selections)
			iferr ! =nil {
				return
			}
		default:
			err = fmt.Errorf("getSelectedFields: found unexpected selection type %v", s)
			return}}return
}
Copy the code

The last

Graphql query is realized by graphQL-go library, and CRUD operation is realized by using type, input and enum parameters. Microservices are developed in two ways: restful and GraphQL, which complement each other, such as uploading, Websocket and other interface mixing modes. Example code: GitHub

Example environment go:1.13, editor vsCode GraphQL official website implementation of JavaScript, using typescript strong type code. If you do not know the syntax, it is recommended to look at JavaScript basic SDL file writing.

About learning

Golang

  • GraphQL-go-godoc
  • Golang Gin GraphQL builds API framework

JavaScript

  • Graphql – js – graphql website
  • Graphql – js – graphql Chinese website
  • Node is based on the GraphQL API server for Express
  • Getting started with GraphQL is enough

Java

  • GraphQL Java is based on SpringBoot practices