From eba3861ec122389c804dbdb324e281aebd6f05c3 Mon Sep 17 00:00:00 2001 From: Vincent Composieux Date: Thu, 22 Jun 2017 14:51:26 +0200 Subject: [PATCH] Added GraphQL API in Go article --- ...07-construire-structurer-api-graphql-go.md | 442 +++++++++++++++++ ...6-15-construct-structure-go-graphql-api.md | 446 ++++++++++++++++++ 2 files changed, 888 insertions(+) create mode 100644 _posts/2017-06-07-construire-structurer-api-graphql-go.md create mode 100644 _posts/2017-06-15-construct-structure-go-graphql-api.md diff --git a/_posts/2017-06-07-construire-structurer-api-graphql-go.md b/_posts/2017-06-07-construire-structurer-api-graphql-go.md new file mode 100644 index 000000000..0dd50ccba --- /dev/null +++ b/_posts/2017-06-07-construire-structurer-api-graphql-go.md @@ -0,0 +1,442 @@ +--- +layout: post +title: "Construire et structurer une API GraphQL en Go" +permalink: /fr/construire-structurer-api-graphql-go/ +author: vcomposieux +date: '2017-06-07 12:00:00 +0100' +date_gmt: '2017-06-07 12:00:00 +0100' +categories: + - Go +tags: + - api + - golang + - graphql +--- +GraphQL est disponible depuis maintenant presque 2 ans et les applications qui l'utilisent se font toujours assez rare. +Pourtant, cette implémentation proposée par Facebook offre de nombreuses possibilités que ne permet pas une API REST. + +# Introduction + +L'objectif de cet article n'est pas de vous expliquer ce qu'est GraphQL, la documentation située à l'adresse http://graphql.org/learn l'explique déjà très bien ! + +Je me suis donc intéressé à construire une API GraphQL, et tant qu'à avoir une API performante, j'ai choisi le langage Go pour la développer, à l'aide de la librairie `graphql-go` (https://github.com/graphql-go/graphql). + +# Structure de fichiers de notre API + +La première chose (et pas des moindres) à prendre en compte lorsque l'on souhaite développer une application est la structure de celle-ci. + +En effet, notre API va être amenée à évoluer, nous allons avoir de plus en plus d'éléments à fournir à nos applications et peut-être allons-nous souhaiter ajouter des composants (pour sécuriser notre API, pour logger des informations, pour limiter le nombre de requêtes, etc ...). + +Ainsi, voici l'arborescence que je vous propose pour notre API : + +```bash +. +├── app +│   ├── config.go +│   ├── config.json +│   └── config_test.go +├── security +│   ├── security.go +│   └── security_test.go +├── mutations +│   ├── mutations.go +│   ├── mutations_test.go +│   ├── user.go +│   └── user_test.go +├── queries +│   ├── queries.go +│   ├── queries_test.go +│   ├── user.go +│   └── user_test.go +├── types +│   ├── role.go +│   ├── role_test.go +│   ├── user.go +│   └── user_test.go +└── main.go +``` + +Nous retrouvons ici : +* "app/" qui comprendra tout ce qui sera nécessaire à notre application (API), principalement un fichier de configuration (JSON) `config.json` ainsi que le fichier Go permettant de charger ce JSON, +* "security/" permettra de regrouper les classes liées à la sécurisation de notre API, +* "mutations/" permettra de regrouper toutes les mutations GraphQL (modifications de données), +* "queries/" permettra de regrouper toutes les requêtes GraphQL de sélection de données, +* "types/" permettra de regrouper les structures Go utilisées lors de nos mutations ou requêtes. + +Enfin, nous retrouvons bien sûr à la racine `main.go` qui est le point d'entrée de notre API. +Nous allons d'ailleurs commencer dès maintenant à construire notre API ! + +# Point d'entrée de l'API + +Pour construire notre API, nous allons avoir besoin dans un premier temps d'importer le package "net/http" (car notre API GraphQL va être distribuée en HTTP) ainsi que les librairies graphql-go : + +```go +package main + +import ( + "log" + "net/http" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/handler" +) + +func main() { + // Todo: Implement GraphQL handler + + http.Handle("/", httpHandler) + log.Print("ready: listening...\n") + + http.ListenAndServe(":8383", nil) +} +``` + +Vous remarquerez ici qu'il nous manque la variable `httpHandler`, qui sera en fait le handler HTTP GraphQL qui sera exécuté pour chaque requête sur "/". Aussi, nous précisons ici que nous allons écouter sur le port 8383, libre à vous de mettre celui que vous souhaitez. + +Notre `httpHandler` va avoir besoin d'un schéma dans lequel nous allons spécifier deux points d'entrée : un pour les requêtes et un second pour les mutations : + +```go +schemaConfig := graphql.SchemaConfig{ + Query: graphql.NewObject(graphql.ObjectConfig{ + Name: "RootQuery", + Fields: queries.GetRootFields(), + }), + Mutation: graphql.NewObject(graphql.ObjectConfig{ + Name: "RootMutation", + Fields: mutations.GetRootFields(), + }), +} + +schema, err := graphql.NewSchema(schemaConfig) + +if err != nil { + log.Fatalf("Failed to create new schema, error: %v", err) +} + +httpHandler := handler.New(&handler.Config{ + Schema: &schema +}) +``` + +Dans le cas ou vous n'avez aucune modifications de données mais uniquement des requêtes de sélection, vous pouvez bien sûr supprimer la section concernant les mutations. + +Ici, il nous manque `queries.GetRootFields()` ainsi que `mutations.GetRootFields()`. Ces méthodes vont nous permettre de définir toutes les `queries` et `mutations` que nous allons définir par la suite. + +Plutôt que d'alourdir le fichier `main.go`, j'ai choisi de les déposer sous `queries/queries.go` et `mutations/mutations.go`. + +# Structures de données + +Avant de commencer à écrire notre première requête, nous devons définir notre modèles de données. + +Dans cet article, nous allons partir sur des données utilisateur ("user") avec un identifiant, un prénom et un nom. Cela donne nous pour notre fichier `types/user.go` : + +```go +package types + +import ( + "github.com/graphql-go/graphql" +) + +// User type definition. +type User struct { + ID int `db:"id" json:"id"` + Firstname string `db:"firstname" json:"firstname"` + Lastname string `db:"lastname" json:"lastname"` +} + +// UserType is the GraphQL schema for the user type. +var UserType = graphql.NewObject(graphql.ObjectConfig{ + Name: "User", + Fields: graphql.Fields{ + "id": &graphql.Field{Type: graphql.Int}, + "firstname": &graphql.Field{Type: graphql.String}, + "lastname": &graphql.Field{Type: graphql.String}, + }, +}) +``` + +Nous avons ici définis deux choses : +* Une structure Go, qui sera utilisée par notre base de données et afin de renvoyer les données de notre API au format JSON, +* Un object `UserType` qui sera utilisé par notre API GraphQL afin d'indiquer les champs qui peuvent être retournés aux applications. + +À l'aide de ce modèle de données, nous sommes maintenant prêts à construire notre première requête GraphQL ! + +# Requêtes + +Commençons par éditer le fichier `queries/queries.go` afin d'ajouter une requête `user` qui sera chargée de retourner nos données utilisateur : + +```go +package queries + +import ( + "github.com/graphql-go/graphql" +) + +// GetRootFields returns all the available queries. +func GetRootFields() graphql.Fields { + return graphql.Fields{ + "user": GetUserQuery(), + } +} +``` + +Nous avons donc ajoutés un nouveau champ à notre requête principale écrite précédemment (RootQuery) nommé `user` et qui fera appel à la fonction `GetUserQuery()`. + +Nous allons maintenant définir cette fonction et son comportement dans un fichier dédié sous `queries/user.go` : + +```go +package queries + +import ( + "../types" + + "github.com/graphql-go/graphql" +) + +// GetUserQuery returns the queries available against user type. +func GetUserQuery() *graphql.Field { + return &graphql.Field{ + Type: graphql.NewList(types.UserType), + Resolve: func(params graphql.ResolveParams) (interface{}, error) { + var users []types.User + + // ... Implémenter la logique de base de données ici + + return users, nil + }, + } +} +``` + +Notre première requête est prête : nous allons utiliser le type de données `UserType`, il ne vous reste plus qu'à implémenter la logique de retour de vos données ! + +Vous pouvez à cet endroit faire un appel à tout outil de stockage de vos données : bases de données relationnelles ou non, SQL ou non, fichier, mémoire, tout est envisageable. + +# Ajouter des relations à votre API + +Imaginons maintenant que vous ayez des roles (pour gérer des accès à certaines ressources) associés à vos utilisateurs. + +Vous pouvez également demander à votre API de retourner ceux-ci. +Pour cela, nous allons commencer par implémenter une nouvelle structure `Role` ainsi qu'un nouveau type `RoleType` pour GraphQL. + +Créez donc le fichier `types/role.go` avec le code suivant : + +```go +package types + +import ( + "github.com/graphql-go/graphql" +) + +// Role type definition. +type Role struct { + ID int `db:"id" json:"id"` + Name string `db:"name" json:"name"` +} + +// RoleType is the GraphQL schema for the user type. +var RoleType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Role", + Fields: graphql.Fields{ + "id": &graphql.Field{Type: graphql.Int}, + "name": &graphql.Field{Type: graphql.String}, + }, +}) +``` + +Voilà qui est fait. Il faut maintenant que nous spécifions à notre `UserType` qu'il est possible d'obtenir les roles de l'utilisateur. + +Pour cela, éditez le fichier `types/user.go` et ajoutez une nouvelle section `graphql.Field` vers votre `RoleType` : + +```go +var UserType = graphql.NewObject(graphql.ObjectConfig{ + Name: "User", + Fields: graphql.Fields{ + // ... already defined fields + "roles": &graphql.Field{ + Type: graphql.NewList(RoleType), + Resolve: func(params graphql.ResolveParams) (interface{}, error) { + var roles []Role + + // userID := params.Source.(User).ID + // Implement logic to retrieve user associated roles from user id here. + + return roles, nil + }, + }, + }, +}) +``` + +Notez ici que le `Type` spécifié est un `graphql.NewList(RoleType)` car nous allons retourner une liste de roles et non pas un seul role. + +Pour effectuer votre requête, vous pouvez utiliser `params.Source` pour obtenir les informations de l'élément principal (ici, l'utilisateur) et ainsi obtenir vos données liées à cet utilisateur. + +Enfin, ce qui est intéressant ici est que le requêtage de données (roles) sera effectué uniquement si le client effectuant la requête GraphQL demande à obtenir les roles. + +# Effectuer des appels à votre API + +À partir de là, vous pouvez donc intéroger votre API avec la requête suivante : + +```bash +curl + -X POST + -H 'Content-Type: application/json' + -d '{"query": "query { users { id,firstname,lastname,roles{name} } }"}' + http://localhost:8383/ + +{"data":{"user":[{"id":1,"firstname":"Vincent","lastname":"COMPOSIEUX","roles":[]}, ...]}} +``` + +Bien entendu, uniquement les champs demandés dans la requête vous seront retournés, c'est le principe. + +GraphQL offre bien sûr des possibilités intéressantes au niveau des requêtes avec notamment des aliases, variables et fragments qui ne sont pas l'objectif de cet article mais je vous invite à faire un tour dans la documentation, ça se comprend très simplement facilement : + +* Aliases : http://graphql.org/learn/queries/#aliases +* Fragments : http://graphql.org/learn/queries/#fragments +* Variables : http://graphql.org/learn/queries/#variables + +# Mutations + +Côté mutations, le fonctionnement est identique aux requêtes. Nous allons donc créer notre première mutation et vous allez voir que ça ressemble beaucoup aux queries. + +Créez le fichier "mutations/mutations.go" et spécifions notre `RootMutation` avec notre fonction `GetRootFields()` : + +```go +package mutations + +import ( + "github.com/graphql-go/graphql" +) + +// GetRootFields returns all the available mutations. +func GetRootFields() graphql.Fields { + return graphql.Fields{ + "createUser": GetCreateUserMutation(), + } +} +``` + +Ici, nous allons créer une mutation pour ajouter un nouvel utilisateur dans notre base de données. + +Déclarons donc maintenant la fonction `GetCreateUserMutation()` dans le fichier `mutations/user.go` : + +```go +package mutations + +import ( + "../types" + + "github.com/graphql-go/graphql" +) + +// GetCreateUserMutation creates a new user and returns it. +func GetCreateUserMutation() *graphql.Field { + return &graphql.Field{ + Type: types.UserType, + Args: graphql.FieldConfigArgument{ + "firstname": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.String), + }, + "lastname": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.String), + }, + }, + Resolve: func(params graphql.ResolveParams) (interface{}, error) { + user := &types.User{ + Firstname: params.Args["firstname"].(string), + Lastname: params.Args["lastname"].(string), + } + + // Add your user in database here + + return user, nil + }, + } +} +``` + +Votre mutation est prête à être utilisée ! + +Comme vous pouvez le remarquer, nous avons ici ajoutés une section `Args` qui nous permet de définir des arguments à notre fonction, par exemple : `createUser(firstname: "John", lastname: "Snow")`. + +Il est ensuite possible de tester votre API en effectuant la requête HTTP suivante : + +```bash +curl + -X POST + -H 'Content-Type: application/json' + -d '{"query": "mutation { createUser(firstname: \"John\", lastname: \"Snow\") { id,firstname,lastname } }"}' + http://localhost:8383 +``` + +Vous pouvez bien sûr choisir d'obtenir en retour uniquement l'identifiant de l'utilisateur nouvellement créé. + +# Securité + +La plupart de vos APIs ne sont certainement pas publiques, il vous faut donc y ajouter un composant de sécurité, et c'est ce que nous allons faire ici en intégrant une authentification JWT (https://jwt.io/). + +Nous allons utiliser la librairie `dgrijalva/jwt-go` (https://github.com/dgrijalva/jwt-go) afin de simplifier l'intégration de JWT dans notre application. + +Ajoutez simplement dans votre fichier `security/security.go` le contenu suivant : + +```go +package security + +import ( + "fmt" + "log" + "net/http" + + jwt "github.com/dgrijalva/jwt-go" +) + +// Handle security middleware aims to implement a JWT authentication. +func Handle(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + tokenString := r.Header.Get("Authorization")[7:] // 7 corresponds to "Bearer " + + token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + + var secret = "my-high-security-secret" // Prefer to store this secret in a configuration file + + return []byte(secret), nil + }) + + if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { + log.Printf("JWT Authenticated OK (app: %s)", claims["app"]) + + next.ServeHTTP(w, r) + } + }) +} +``` + +Ici, nous récupérons le token reçu dans le header `Authorization: Bearer xxx` et allons l'utiliser pour le comparer avec notre secret. + +Dans le cas ou le token est valide, l'application continuera à exécuter le handler HTTP, sinon, une erreur sera levée. + +Pour utiliser ce composant de sécurité, il faut repasser sur notre fichier `main.go` afin d'importer le répertoire `security` et de modifier : + +```go +http.Handle("/", httpHandler) +``` + +en : + +```go +http.Handle("/", security.Handle(httpHandler)) +``` + +Vous disposez maintenant d'une API GraphQL performante et sécurisée ! + +# Conclusion + +L'implémentation de GraphQL en Go est plutôt simple à prendre en main et les performances du langage permettent de construire une API performante. + +Il nous est également possible de bien structurer celle-ci afin de séparer notamment les queries, les mutations et les autres composants. + +Si vous voulez tester cette structure, les sources sont disponibles ici : https://github.com/eko/graphql-go-structure diff --git a/_posts/2017-06-15-construct-structure-go-graphql-api.md b/_posts/2017-06-15-construct-structure-go-graphql-api.md new file mode 100644 index 000000000..19c8d86ed --- /dev/null +++ b/_posts/2017-06-15-construct-structure-go-graphql-api.md @@ -0,0 +1,446 @@ +--- +layout: post +title: "Construct and structure a Go GraphQL API" +permalink: /en/construct-structure-go-graphql-api/ +author: vcomposieux +date: '2017-06-15 12:00:00 +0100' +date_gmt: '2017-06-15 12:00:00 +0100' +categories: + - Go +tags: + - api + - golang + - graphql +--- +GraphQL was released 2 years ago and applications that use it are still rare. +However, this implementation proposed by Facebook offers many possibilities that are not available in REST APIs. + +# Introduction + +The goal of this blog post is not to explain from the basics what is GraphQL because official documentation of the implementation located at http://graphql.org/learn explain it really well! + +I was interested of constructing a GraphQL API and I also wanted to have a performant API so I choose the Go language to develop it using the `graphql-go` library available here: https://github.com/graphql-go/graphql. + +# File structure of our API + +The first thing to do (and not least!) is to create a great understandable and re-usable file structure. + +Indeed, our API will have to evolve in the future, for sure, so we will have to add more and more files into it such as maybe a security component, a rate limiter component, something to log requests, and so many more. + +Here is the file structure I propose to create in this blog post that seems to me to be a great start: + +```bash +. +├── app +│   ├── config.go +│   ├── config.json +│   └── config_test.go +├── security +│   ├── security.go +│   └── security_test.go +├── mutations +│   ├── mutations.go +│   ├── mutations_test.go +│   ├── user.go +│   └── user_test.go +├── queries +│   ├── queries.go +│   ├── queries_test.go +│   ├── user.go +│   └── user_test.go +├── types +│   ├── role.go +│   ├── role_test.go +│   ├── user.go +│   └── user_test.go +└── main.go +``` + +Here is what we have here: +* "app/" will contains all Go classes and configuration files that will be needed to get our application (API) to work so we will have mainly a configuration file (JSON) `config.json` and also a `config.go` file that will load this JSON, +* "security/" will group Go classes that will be used for our security component, +* "mutations/" will group all of our GraphQL mutations (data changes), +* "queries/" will group all of our GraphQL queries (selecting data), +* "types/" will group all of our Go structures and types used by GraphQL by both queries and mutations. + +Finally, we will find at the root directory the `main.go` file which will be the entry point of our API. + +So now that everything is clear, let's start writing our API! + +# API entry point + +To construct our API, we will need in a first time the Go `net/http` package (because our GraphQL API will be accessible over HTTP) and also the `graphql-go` library: + +```go +package main + +import ( + "log" + "net/http" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/handler" +) + +func main() { + // Todo: Implement GraphQL handler + + http.Handle("/", httpHandler) + log.Print("ready: listening...\n") + + http.ListenAndServe(":8383", nil) +} +``` + +You can note here that the `httpHandler` variable that will be the HTTP handler used by GraphQL and will be executed for each request that will be made over the "/" URL. Also, we have to give a port number here (8383) on which our API will listen to. + +Let's implement the `httpHandler` which will need a schema in which we will specify two entry points: a first for the queries and a second for the mutations: + +```go +schemaConfig := graphql.SchemaConfig{ + Query: graphql.NewObject(graphql.ObjectConfig{ + Name: "RootQuery", + Fields: queries.GetRootFields(), + }), + Mutation: graphql.NewObject(graphql.ObjectConfig{ + Name: "RootMutation", + Fields: mutations.GetRootFields(), + }), +} + +schema, err := graphql.NewSchema(schemaConfig) + +if err != nil { + log.Fatalf("Failed to create new schema, error: %v", err) +} + +httpHandler := handler.New(&handler.Config{ + Schema: &schema +}) +``` + +In the case you have no data modifications but only queries, you can of course remove the mutations section from the code. + +Here, we are missing the `queries.GetRootFields()` and also the `mutations.GetRootFields()` methods. These methods will allow us to define our `queries` and `mutations` that will be used in our API. + +Rather than weighing down our `main.go` file with these things, I chose to put them into two separate files: `queries/queries.go` and `mutations/mutations.go`. + +# Data structures + +Before to go writting our first query, we will need to define our data model. + +In this blog post, we will return user data with an identifier, a firstname and a lastname. So we will have to write our first file under `types/user.go`: + +```go +package types + +import ( + "github.com/graphql-go/graphql" +) + +// User type definition. +type User struct { + ID int `db:"id" json:"id"` + Firstname string `db:"firstname" json:"firstname"` + Lastname string `db:"lastname" json:"lastname"` +} + +// UserType is the GraphQL schema for the user type. +var UserType = graphql.NewObject(graphql.ObjectConfig{ + Name: "User", + Fields: graphql.Fields{ + "id": &graphql.Field{Type: graphql.Int}, + "firstname": &graphql.Field{Type: graphql.String}, + "lastname": &graphql.Field{Type: graphql.String}, + }, +}) +``` + +We declare two things here: +* A Go struct that will be used for mapping data from our database and to return data to the client in a JSON format, +* A `UserType` GraphQL Field that will be used by our GraphQL API to specify fields that can be returned by our API. + +By using the data model, we are now (finally) able to write our first query! + +# Queries + +Let's edit the `queries/queries.go` file in order to add a `user` named query that will be charged to return our user data: + +```go +package queries + +import ( + "github.com/graphql-go/graphql" +) + +// GetRootFields returns all the available queries. +func GetRootFields() graphql.Fields { + return graphql.Fields{ + "user": GetUserQuery(), + } +} +``` + +We've added a new field in our root query previously written named `user` and that will call the `GetUserQuery()` function to return its fields. This function will be defined into another file. + +We will now define this function and its behavior into another dedicated file called `queries/user.go`: + +```go +package queries + +import ( + "../types" + + "github.com/graphql-go/graphql" +) + +// GetUserQuery returns the queries available against user type. +func GetUserQuery() *graphql.Field { + return &graphql.Field{ + Type: graphql.NewList(types.UserType), + Resolve: func(params graphql.ResolveParams) (interface{}, error) { + var users []types.User + + // ... Implement the way you want to obtain your data here. + + return users, nil + }, + } +} +``` + +Our first query is ready: we will use the data model `UserType` for it so you just have to implement the logic to retrieve your data here. + +At this place, you can make a call on every storage engine you want to obtain your data: relational databases or not, SQL or not, file storage, memory storage, everything is possible. + +# Add relations to your API + +Let's now imagine that you have some roles defined for your users (in order to manage access to some resources). + +You can also ask to your GraphQL API to return them. + +To do that, we will implement a new `Role` struct and also a `RoleType` used by GraphQL. + +Create the `types/role.go` containing following code: + +```go +package types + +import ( + "github.com/graphql-go/graphql" +) + +// Role type definition. +type Role struct { + ID int `db:"id" json:"id"` + Name string `db:"name" json:"name"` +} + +// RoleType is the GraphQL schema for the user type. +var RoleType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Role", + Fields: graphql.Fields{ + "id": &graphql.Field{Type: graphql.Int}, + "name": &graphql.Field{Type: graphql.String}, + }, +}) +``` + +We now have to specify to our `UserType` and we can also obtain some roles linked to the user. + +To do that, edit the `types/user.go` file and add a new `graphql.Field` section to `RoleType`: + +```go +var UserType = graphql.NewObject(graphql.ObjectConfig{ + Name: "User", + Fields: graphql.Fields{ + // ... already defined fields + "roles": &graphql.Field{ + Type: graphql.NewList(RoleType), + Resolve: func(params graphql.ResolveParams) (interface{}, error) { + var roles []Role + + // userID := params.Source.(User).ID + // Implement logic to retrieve user associated roles from user id here. + + return roles, nil + }, + }, + }, +}) +``` + +Please note that the `Type` specified for this field is a `graphql.NewList(RoleType)` because we will return a roles list and not a single role entry. + +To request against user roles using the current user data, you can use the available `params.Source`. + +Finally, what is interesting here is that roles queries will be only done if the roles data are requested by the GraphQL API client. + +# Make calls to your API + +Starting from there, you are able to call your API with a query like that: + +```bash +curl + -X POST + -H 'Content-Type: application/json' + -d '{"query": "query { users { id,firstname,lastname,roles{name} } }"}' + http://localhost:8383/ + +{"data":{"user":[{"id":1,"firstname":"Vincent","lastname":"COMPOSIEUX","roles":[]}, ...]}} +``` + +Of course, as said previously, only query specified fields will be returned, that's the GraphQL main principle. + +GraphQL also offers a lot of great things to help you writing neat queries with among others aliases, variables and fragments. + +You can read documentation of these parts here: + +* Aliases : http://graphql.org/learn/queries/#aliases +* Fragments : http://graphql.org/learn/queries/#fragments +* Variables : http://graphql.org/learn/queries/#variables + +# Mutations + +About mutations, le fonctionnement est identique aux requêtes. Nous allons donc créer notre première mutation et vous allez voir que ça ressemble beaucoup aux queries. + +Create file `mutations/mutations.go` and specify the `RootMutation` returned by `GetRootFields()`: + +```go +package mutations + +import ( + "github.com/graphql-go/graphql" +) + +// GetRootFields returns all the available mutations. +func GetRootFields() graphql.Fields { + return graphql.Fields{ + "createUser": GetCreateUserMutation(), + } +} +``` + +Then, we will create a mutation to create a new user in our database. + +Let's declare the `GetCreateUserMutation()` function in file `mutations/user.go`: + +```go +package mutations + +import ( + "../types" + + "github.com/graphql-go/graphql" +) + +// GetCreateUserMutation creates a new user and returns it. +func GetCreateUserMutation() *graphql.Field { + return &graphql.Field{ + Type: types.UserType, + Args: graphql.FieldConfigArgument{ + "firstname": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.String), + }, + "lastname": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.String), + }, + }, + Resolve: func(params graphql.ResolveParams) (interface{}, error) { + user := &types.User{ + Firstname: params.Args["firstname"].(string), + Lastname: params.Args["lastname"].(string), + } + + // Add your user in database here + + return user, nil + }, + } +} +``` + +Your mutation is now ready to be used! + +As you can notice, we've added an `Args` section here that allows us to define some arguments to our function, such as: `createUser(firstname: "John", lastname: "Snow")`. + +This is of course possible to test our API by calling it now using the following way: + +```bash +curl + -X POST + -H 'Content-Type: application/json' + -d '{"query": "mutation { createUser(firstname: \"John\", lastname: \"Snow\") { id,firstname,lastname } }"}' + http://localhost:8383 +``` + +You can of course choose only the identified of the newly created user if needed. + +# Security + +Most of your APIs are certainly not public so you also need a component to handle security and that's whay we will do by using a JWT authentication (https://jwt.io/). + +We will use the `dgrijalva/jwt-go` library (https://github.com/dgrijalva/jwt-go) in order to simplify the use of JWT in our Go application. + +Simply add in your `security/security.go` file the following content: + +```go +package security + +import ( + "fmt" + "log" + "net/http" + + jwt "github.com/dgrijalva/jwt-go" +) + +// Handle security middleware aims to implement a JWT authentication. +func Handle(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + tokenString := r.Header.Get("Authorization")[7:] // 7 corresponds to "Bearer " + + token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + + var secret = "my-high-security-secret" // Prefer to store this secret in a configuration file + + return []byte(secret), nil + }) + + if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { + log.Printf("JWT Authenticated OK (app: %s)", claims["app"]) + + next.ServeHTTP(w, r) + } + }) +} +``` + +We retrieve the token sent in the `Authorization: Bearer xxx` header by the client and will compare it with a secret we've stored in our configuration file. + +In the case the token is valid, the application will continue to execute the HTTP handler, elsewhere, an error will be thrown. + +In order to use this security component, we will have to update our `main.go` file to import the `security` folder and also modify: + +```go +http.Handle("/", httpHandler) +``` + +with: + +```go +http.Handle("/", security.Handle(httpHandler)) +``` + +You now have a functional and secured GraphQL API! + +# Conclusion + +The GraphQL implementation using Go is quite simple to do thank to the available library and language performances allows to construct powerful APIs. + +It is also possible to well structure your API in order to separate, especially for queries, mutations and other components. + +If you want to give it a try, sources of this blog post are available here: https://github.com/eko/graphql-go-structure