
Hola a todos! Hay muchos artículos sobre GraphQL en Habr, pero después de leerlos, descubrí que todos omiten un lenguaje tan maravilloso como Go. Hoy intentaré corregir este malentendido. Para hacer esto, escribiremos una API en Go usando GraphQL.
En pocas palabras: GraphQL es un lenguaje de consulta para construir una API que describe en qué forma solicitar y devolver datos (información más detallada sobre el recurso oficial graphql.imtqy.com y en el concentrador )
Puede argumentar que GraphQL o REST es mejor aquí.
Tendremos la API clásica: CRUD (Crear, Leer, Actualizar, Eliminar) agregar, recibir, editar y eliminar productos en la tienda en línea.
En el lado del servidor, utilizaremos la implementación lista de GraphQL graphql-go
Primero necesitas descargar graphql-go, esto se puede hacer con el comando
go get github.com/graphql-go/graphql
A continuación, describimos la estructura del producto (en forma simplificada)
type Product struct { ID int64 `json:"id"` Name string `json:"name"` Info string `json:"info,omitempty"` Price float64 `json:"price"` }
ID
- identificador único, Name
- nombre, Info
- información del producto, Price
- precio
Lo primero que debe hacer es llamar al método Do
, que acepta un esquema de datos y parámetros de consulta como parámetros de entrada. Y nos devolverá los datos resultantes (para su posterior transmisión al cliente)
result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, })
Código completo func executeQuery(query string, schema graphql.Schema) *graphql.Result { result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) if len(result.Errors) > 0 { fmt.Printf("errors: %v", result.Errors) } return result } func main() { http.HandleFunc("/product", func(w http.ResponseWriter, r *http.Request) { result := executeQuery(r.URL.Query().Get("query"), schema) json.NewEncoder(w).Encode(result) }) http.ListenAndServe(":8080", nil) }
Schema
- esquema de datos, RequestString
- valor del parámetro de cadena de consulta, en nuestro caso, valor de query
Esquema
Un esquema acepta dos tipos de datos raíz: Query
: datos inmutables, Mutation
: datos mutables
var schema, _ = graphql.NewSchema( graphql.SchemaConfig{ Query: queryType, Mutation: mutationType, }, )
Consulta
Query
se usa para leer (y solo leer) datos. Usando Query
especificamos qué datos debe devolver el servidor.
Escribiremos una implementación del tipo de datos Query
, en nuestro caso contendrá campos con información sobre un solo producto (producto) y una lista de productos (lista)
var queryType = graphql.NewObject( graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "product": &graphql.Field{ Type: productType, Description: "Get product by id",
El tipo queryType contiene el Name
y los Fields
requeridos, así como la Description
opcional (utilizada para la documentación)
A su vez, el campo Fields
también contiene el campo Type
requerido y los Args
opcionales Args
, Resolve
y Description
Args (argumentos)
Argumentos: una lista de parámetros transferidos del cliente al servidor y que afectan el resultado de los datos devueltos. Los argumentos están vinculados a un campo específico. Y los argumentos se pueden pasar tanto en Query
como en Mutation
.
?query={product(id:1){name,info,price}}
En este caso, el argumento id
para el campo del product
con un valor de 1 indica que es necesario devolver el producto con el identificador especificado.
Para la list
se omiten list
argumentos, pero en una aplicación real puede ser, por ejemplo: limit
y offset
.
Resolver (reconocimiento)
Toda la lógica de trabajar con datos (por ejemplo, consultas de bases de datos, procesamiento y filtrado) está en los reconocedores, son ellos quienes devuelven los datos que se transmitirán al cliente como respuesta a la solicitud.
Tipo
GraphQL usa su sistema de tipos para describir datos. Puede usar los tipos básicos String
, Int
, Float
, Boolean
y los suyos (personalizados). Para nuestro ejemplo, necesitaremos un tipo de Product
personalizado, que describirá todas las propiedades del producto.
var productType = graphql.NewObject( graphql.ObjectConfig{ Name: "Product", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.Int, }, "name": &graphql.Field{ Type: graphql.String, }, "info": &graphql.Field{ Type: graphql.String, }, "price": &graphql.Field{ Type: graphql.Float, }, }, }, )
Para cada campo, se especifica el tipo base, en este caso graphql.Int
, graphql.String
, graphql.Float
.
El número de campos anidados no está limitado, por lo que puede implementar un sistema gráfico de cualquier nivel.
Mutación
Las mutaciones son estos datos mutables, que incluyen: adición, edición y eliminación. De lo contrario, las mutaciones son muy similares a las consultas regulares: también toman argumentos de Args
y devuelven datos de Args
como respuesta a la consulta.
Escribamos mutaciones para nuestros productos. var mutationType = graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ "create": &graphql.Field{ Type: productType, Description: "Create new product", Args: graphql.FieldConfigArgument{ "name": &graphql.ArgumentConfig{ Type: graphql.NewNonNull(graphql.String),
Todo similar a queryType
. Solo hay un tipo de característica pequeña graphql.NewNonNull(graphql.Int)
, que nos dice que este campo no puede estar vacío (similar a NOT NULL
en MySQL)
Eso es todo. Ahora tenemos una API Go CRUD simple para trabajar con productos. No usamos la base de datos para este ejemplo, pero vimos cómo crear un modelo de datos y manipularlos usando mutaciones.
Ejemplos
Si descargó la fuente a través de
go get github.com/graphql-go/graphql
solo ve al directorio con un ejemplo
cd examples/crud
y ejecuta la aplicación
go run main.go
Puede usar las siguientes consultas:
Obtener producto por ID
http://localhost:8080/product?query={product(id:1){name,info,price}}
Obtener una lista de productos
http://localhost:8080/product?query={list{id,name,info,price}}
Agregar nuevo producto
http://localhost:8080/product?query=mutation+_{create(name:"Tequila",info:"Strong alcoholic beverage",price:999){id,name,info,price}}
Edición de producto
http://localhost:8080/product?query=mutation+_{update(id:1,price:195){id,name,info,price}}
Eliminar un producto por id
http://localhost:8080/product?query=mutation+_{delete(id:1){id,name,info,price}}
Si usa REST, preste atención a GraphQL como una posible alternativa. Sí, a primera vista parece más difícil, pero vale la pena comenzar y en un par de días dominarás esta tecnología. Al menos será útil.