
Olá pessoal! Existem muitos artigos sobre o GraphQL no Habr, mas, depois de analisá-los, descobri que todos eles ignoram uma linguagem maravilhosa como o Go. Hoje vou tentar corrigir esse mal-entendido. Para fazer isso, escreveremos uma API on Go usando o GraphQL.
Em poucas palavras: GraphQL é uma linguagem de consulta para a criação de uma API que descreve de que forma solicitar e retornar dados (informações mais detalhadas sobre o recurso oficial graphql.imtqy.com e o hub )
Você pode argumentar que GraphQL ou REST é melhor aqui.
Teremos a API clássica: CRUD (criar, ler, atualizar, excluir) adicionar, receber, editar e excluir produtos na loja online.
No lado do servidor, usaremos a pronta implementação do GraphQL graphql-go
Primeiro você precisa baixar o graphql-go, isso pode ser feito com o comando
go get github.com/graphql-go/graphql
A seguir, descrevemos a estrutura do produto (de forma simplificada)
type Product struct { ID int64 `json:"id"` Name string `json:"name"` Info string `json:"info,omitempty"` Price float64 `json:"price"` }
ID
- identificador exclusivo, Name
- nome, Info
- informações sobre o produto, Price
- preço
A primeira coisa a fazer é chamar o método Do
, que aceita um esquema de dados e consulta parâmetros como parâmetros de entrada. E ele retornará os dados resultantes para nós (para posterior transmissão ao 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
- Schema
dados, RequestString
- valor do parâmetro string de consulta, no nosso caso, valor da query
Esquema
Um esquema aceita dois tipos de dados raiz: Query
- dados imutáveis, Mutation
- dados mutáveis
var schema, _ = graphql.NewSchema( graphql.SchemaConfig{ Query: queryType, Mutation: mutationType, }, )
Consulta
Query
é usada para ler (e apenas ler) dados. Usando Query
especificamos quais dados o servidor deve retornar.
Escreveremos uma implementação do tipo de dados Query
, no nosso caso, conterá campos com informações sobre um único produto (produto) e uma lista de mercadorias (lista)
var queryType = graphql.NewObject( graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "product": &graphql.Field{ Type: productType, Description: "Get product by id",
O tipo queryType contém o Name
e os Fields
necessários, bem como a Description
opcional (usada para a documentação)
Por sua vez, o campo Fields
também contém o campo Type
obrigatório e os campos Args
, Resolve
e Description
opcionais
Args (argumentos)
Argumentos - uma lista de parâmetros transferidos do cliente para o servidor e afetando o resultado dos dados retornados. Os argumentos estão vinculados a um campo específico. E os argumentos podem ser passados na Query
e na Mutation
.
?query={product(id:1){name,info,price}}
Nesse caso, o argumento id
para o campo do product
com o valor 1 indica que é necessário retornar o produto com o identificador especificado.
Para a list
argumentos são omitidos, mas em um aplicativo real, pode ser, por exemplo: limit
e offset
.
Resolução (reconhecimento)
Toda a lógica de trabalhar com dados (por exemplo, consultas de banco de dados, processamento e filtragem) está nos reconhecedores, são eles que retornam os dados que serão transmitidos ao cliente como resposta à solicitação.
Tipo
O GraphQL usa seu sistema de tipos para descrever dados. Você pode usar os tipos básicos String
, Int
, Float
, Boolean
e seus próprios (personalizados). Para o nosso exemplo, precisaremos de um Product
personalizado, que descreva todas as propriedades do produto
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, o tipo de base é especificado, neste caso, graphql.String
, graphql.Float
, graphql.Float
.
O número de campos aninhados não é limitado, portanto, você pode implementar um sistema gráfico de qualquer nível.
Mutação
Mutações são esses dados mutáveis, que incluem: adição, edição e exclusão. Caso contrário, as mutações são muito semelhantes às consultas regulares: elas também Args
argumentos de Args
e retornam dados de Resolve
como resposta à consulta.
Vamos escrever mutações para nossos produtos. 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),
Tudo semelhante ao queryType
. Existe apenas um pequeno tipo de recurso graphql.NewNonNull(graphql.Int)
, que indica que esse campo não pode estar vazio (semelhante a NOT NULL
no MySQL)
Só isso. Agora, temos uma API Go CRUD simples para trabalhar com mercadorias. Não usamos o banco de dados para este exemplo, mas vimos como criar um modelo de dados e manipulá-los usando mutações.
Exemplos
Se você baixou a fonte através do
go get github.com/graphql-go/graphql
basta ir ao diretório com um exemplo
cd examples/crud
e execute o aplicativo
go run main.go
Você pode usar as seguintes consultas:
Obtendo produto por ID
http://localhost:8080/product?query={product(id:1){name,info,price}}
Obtendo uma lista de produtos
http://localhost:8080/product?query={list{id,name,info,price}}
Adicionar novo produto
http://localhost:8080/product?query=mutation+_{create(name:"Tequila",info:"Strong alcoholic beverage",price:999){id,name,info,price}}
Edição do produto
http://localhost:8080/product?query=mutation+_{update(id:1,price:195){id,name,info,price}}
Removendo um Produto por ID
http://localhost:8080/product?query=mutation+_{delete(id:1){id,name,info,price}}
Se você usa o REST, preste atenção ao GraphQL como uma possível alternativa. Sim, à primeira vista, parece mais difícil, mas vale a pena começar e em alguns dias você dominará essa tecnologia. Pelo menos será útil.