# GraphQL en Go

## Introducción

[gqlgen](https://gqlgen.com/) es un generador de código GraphQL para Go que simplifica el proceso de construcción de servidores GraphQL. gqlgen se basa en el enfoque "schema first", por lo que puedes definir tu esquema GraphQL en SDL (Schema Definition Language) y luego dejar que la herramienta genere automáticamente el código necesario para resolver consultas, mutaciones y suscripciones.

[Gorm](https://gorm.io/) es un popular ORM (Object Relational Mapping) para Go, diseñado para simplificar las operaciones de base de datos y mejorar la eficiencia del desarrollo. Proporciona una interfaz sencilla y potente para interactuar con bases de datos relacionales, permitiendo a los desarrolladores centrarse en la lógica de la aplicación en lugar de preocuparse por detalles de bajo nivel.

En este tutorial, combinaremos la potencia de gqlgen para la capa GraphQL y Gorm para la persistencia de datos, creando así una API GraphQL robusta y eficiente para gestionar tareas.

## Consideraciones

Este tutorial es completamente práctico, por lo que no se abordará conceptos teóricos; por esta razón, para sacar mayor provecho al tutorial, es conveniente tener alguna experiancia previa en el desarrollo con Go, algún conocimiento básico de GraphQL (queries, mutations, SDL, etc) y conocimiento básico de base de datos relacionales.

## Proyecto

El proyecto consiste en un API Graphql para guardar, consultar, modificar y eliminar datos sobre usuarios y posts. Estableceremos una relación "one to many" de forma que un usuario puede tener muchos posts, y un post pertenece a un usuario. Generaremos las `queries` de forma que al consultar los usuarios podamos acceder a los posts que tienen y, al consultar los posts poder ver los usuarios al que pertenecen. Las `mutations` nos permitirán añadir usuarios y posts, actualizarlos y eliminarlos.

## Instalación y configuración de GQLGEN

Comenzamos creando el directorio e inicializamos el módulo para nuestro proyecto.

```plaintext
mkdir graphql-api-users-posts
cd graphql-api-users-posts
```

Llamé al directorio `graphql-api-users-posts` , una vez dentro de la carpeta, inicializamos el módulo de GO.

```plaintext
go mod init github.com/[tu-nombre-de-usuario]/graphql-api-users-posts
```

Siguiendo la documentación de gqlgen, debemos crear un fichero `tools.go` en la raíz del proyecto con el siguiente código:

```go
//go:build tools
// +build tools

package tools

import (
	_ "github.com/99designs/gqlgen"
)
```

A continuación corremos el comando para installar la dependencia.

```plaintext
go mod tidy
```

Por defecto, instalará la última versión de gqlgen. Ahora corremos el comando para generar el esqueleto del proyecto.

```plaintext
go run github.com/99designs/gqlgen init
```

Este comando generará el siguiente árbol de ficheros.

```plaintext
├── go.mod
├── go.sum
├── gqlgen.yml               - The gqlgen config file, knobs for controlling the generated code.
├── graph
│   ├── generated            - A package that only contains the generated runtime
│   │   └── generated.go
│   ├── model                - A package for all your graph models, generated or otherwise
│   │   └── models_gen.go
│   ├── resolver.go          - The root graph resolver type. This file wont get regenerated
│   ├── schema.graphqls      - Some schema. You can split the schema into as many graphql files as you like
│   └── schema.resolvers.go  - the resolver implementation for schema.graphql
└── server.go
```

El fichero `graph/schema.graphqls` es donde se definen los tipos de datos para nuestros proyecto. Por defecto genera los esquemas para un ToDo. Vamos a modificarlos con los tipos de datos para nuestro proyecto.

## Definición de tipos de datos

Abre el fichero `graph/schema.graphqls` y reemplaza el código por defecto con el siguiente:

```graphql
type User {
  id: Int!
  name: String!
  lastname: String!
  posts: [Post!]!
}

type Post {
  id: Int!
  title: String!
  text: String!
  user: User!
}

input inputUser {
  name: String!
  lastname: String!
}

input inputPost {
  title: String!
  text: String!
  userId: Int!
}

type Query {
  users: [User!]!
  user(id: Int!): User!
  
  posts: [Post!]!
  post(id: Int!): Post!
}

type Mutation {
  createUser(user: inputUser!): User!
  updateUser(id: Int!, user: inputUser!): User!
  deleteUser(id: Int!): User!

  createPost(post: inputPost!): Post!
  updatePost(id: Int!, post: inputPost!): Post!
  deletePost(id: Int!): Post!
}
```

Este código define un esquema GraphQL básico con dos tipos principales, `User` y `Post`, y las operaciones de consulta (`Query`) y mutación (`Mutation`) asociadas. Además, se definen dos tipos de entrada (`inputUser` e `inputPost`) que se utilizan en las mutaciones para proporcionar datos al crear o actualizar usuarios y posts.

A continuación debemos correr el comando para que gqlgen genere los resolvers para cada una de las operaciones definidas en el fichero.

Antes de ejecutar el comando, es conveniente que abras el fichero `graph/schema.resolvers.go` y borres todo el contenido, ya que puede producir algunos problemas a la hora de generar los resolvers.

```plaintext
go run github.com/99designs/gqlgen generate
```

Si todo va bien, al abrir el fichero `graph/schema.resolvers.go` deberías ver el siguiente código:

```go
package graph

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen version v0.17.40

import (
	"context"
	"fmt"

	"github.com/alegrecode/graphql-api-users-posts/graph/model"
)

// CreateUser is the resolver for the createUser field.
func (r *mutationResolver) CreateUser(ctx context.Context, user model.InputUser) (*model.User, error) {
	panic(fmt.Errorf("not implemented: CreateUser - createUser"))
}

// UpdateUser is the resolver for the updateUser field.
func (r *mutationResolver) UpdateUser(ctx context.Context, id int, user model.InputUser) (*model.User, error) {
	panic(fmt.Errorf("not implemented: UpdateUser - updateUser"))
}

// DeleteUser is the resolver for the deleteUser field.
func (r *mutationResolver) DeleteUser(ctx context.Context, id int) (*model.User, error) {
	panic(fmt.Errorf("not implemented: DeleteUser - deleteUser"))
}

// CreatePost is the resolver for the createPost field.
func (r *mutationResolver) CreatePost(ctx context.Context, post model.InputPost) (*model.Post, error) {
	panic(fmt.Errorf("not implemented: CreatePost - createPost"))
}

// UpdatePost is the resolver for the updatePost field.
func (r *mutationResolver) UpdatePost(ctx context.Context, id int, post model.InputPost) (*model.Post, error) {
	panic(fmt.Errorf("not implemented: UpdatePost - updatePost"))
}

// DeletePost is the resolver for the deletePost field.
func (r *mutationResolver) DeletePost(ctx context.Context, id int) (*model.Post, error) {
	panic(fmt.Errorf("not implemented: DeletePost - deletePost"))
}

// Users is the resolver for the users field.
func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
	panic(fmt.Errorf("not implemented: Users - users"))
}

// User is the resolver for the user field.
func (r *queryResolver) User(ctx context.Context, id int) (*model.User, error) {
	panic(fmt.Errorf("not implemented: User - user"))
}

// Posts is the resolver for the posts field.
func (r *queryResolver) Posts(ctx context.Context) ([]*model.Post, error) {
	panic(fmt.Errorf("not implemented: Posts - posts"))
}

// Post is the resolver for the post field.
func (r *queryResolver) Post(ctx context.Context, id int) (*model.Post, error) {
	panic(fmt.Errorf("not implemented: Post - post"))
}

// Mutation returns MutationResolver implementation.
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }

// Query returns QueryResolver implementation.
func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }

type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
```

Este código proporciona la estructura inicial para tus resolvers, generada por gqlgen. Deberemos completar la lógica dentro de cada resolver para que realice las operaciones reales, como crear, actualizar o eliminar datos en nuestra aplicación según lo definido en el esquema GraphQL.

Si abres el fichero `graph/model/models_gen.go` podrás ver el siguiente código generado:

```go
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.

package model

type Post struct {
	ID    int    `json:"id"`
	Title string `json:"title"`
	Text  string `json:"text"`
	User  *User  `json:"user"`
}

type User struct {
	ID       int     `json:"id"`
	Name     string  `json:"name"`
	Lastname string  `json:"lastname"`
	Posts    []*Post `json:"posts"`
}

type InputPost struct {
	Title  string `json:"title"`
	Text   string `json:"text"`
	UserID int    `json:"userId"`
}

type InputUser struct {
	Name     string `json:"name"`
	Lastname string `json:"lastname"`
}
```

Este código define los modelos de datos utilizados en nuestra aplicación GraphQL generada por gqlgen. Estos modelos representan los tipos de datos que se utilizan en las operaciones GraphQL de la aplicación.

Es importante destacar que este código es generado automáticamente por gqlgen y no debes editarlo directamente.

Sin embargo, esto no es conveniente ya que más adelante, debemos modificar los modelos para crear la relación "one to many" cuando utilicemos GORM.

Para resolver esto, vamos a crear nuestros modelos en ficheros a parte y luego le diremos a gqlgen que utilice esos modelos.

## Creación de los modelos

Comencemos creando el modelo `User` . Crea un fichero `graph/model/user.go` y copiemos el código del type `User` generado en `graph/model/models_gen.go` .

```go
package model

type User struct {
	ID       int     `json:"id"`
	Name     string  `json:"name"`
	Lastname string  `json:"lastname"`
	Posts    []*Post `json:"posts"`
}
```

Ahora creamos el modelo `Post` con el mismo procedimiento. Crea un fichero `graph/model/post.go` .

```go
package model

type Post struct {
	ID    int    `json:"id"`
	Title string `json:"title"`
	Text  string `json:"text"`
	User  *User  `json:"user"`
}
```

Ya tenemos nuestros modelos, ahora debemos decirle a gqlgen que utilice estos modelos en lugar de que los genere autmáticamente.

Para ello abre el fichero `gqlgen.yml` y tienes que descomentar la siguiente línea:

```yaml
autobind:
 - "github.com/[tu-nombre-de-usuario]/graphql-api-users-posts/graph/model"
```

La directiva `autobind` especifica el paquete o módulo que contiene los modelos de datos (estructuras Go) que serán utilizados por gqlgen para generar automáticamente código GraphQL y resolvers.

Luego, en la sección "models", añade las siguientes líneas:

```yaml
models:
  Post:
    model: github.com/[tu-nombre-de-usuario]/graphql-api-users-posts/graph/model.Post
  User:
    model: github.com/[tu-nombre-de-usuario]/graphql-api-users-posts/graph/model.User
```

La sección `models` especifica las configuraciones para cada tipo de modelo en la aplicación GraphQL. En este caso, se mencionan los dos modelos: `Post` y `User`. La clave `model` indica la ubicación del modelo en el código fuente del proyecto.

Finalmente, entra al fichero `graph/schema.resolvers.go` , borra el contenido y vuelve a correr el comando para generar los resolvers.

```plaintext
go run github.com/99designs/gqlgen generate
```

Si todo sale bien, al abrir el fichero `graph/model/models_gen.go` podrás ver el siguiente código:

```go
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.

package model

type InputPost struct {
	Title  string `json:"title"`
	Text   string `json:"text"`
	UserID int    `json:"userId"`
}

type InputUser struct {
	Name     string `json:"name"`
	Lastname string `json:"lastname"`
}
```

Como puedes ver, sólo se generaron los tipos de entrada de datos para los posts y los usuarios; esto significa que gqlgen está utilizando los modelos que creamos para generar los resolvers.

Esto es importante ya que podremos realizar las modificaciones en los modelos para crear la relación "one to many" cuando creemos la conexión a la base de datos con GORM.

## Conexión a la base de datos

Comenzamos creando la base de datos. Entra a tu gestor y crea uno para nuestro proyecto.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1701724962490/97a73ab7-fd3f-4e34-9377-ff371c552f5a.png align="center")

Lo llamé `graphql_users_posts` y el cotejamiento, como lo recomienda la documentación de GORM, `utf8mb4` .

Ahora instalamos el paquete de GORM y driver para MySQL.

```plaintext
go get -u gorm.io/gorm

go get gorm.io/driver/mysql
```

Seguimos creando el fichero `database/database.go` para establecer la conexión a la base de datos.

```go
package database

import (
	"github.com/alegrecode/graphql-api-users-posts/graph/model"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var DB *gorm.DB

func Conexion() {
	dsn := "root:@tcp(127.0.0.1:3306)/graphql_users_posts?charset=utf8mb4&parseTime=True&loc=Local"
	DB, _ = gorm.Open(mysql.Open(dsn), &gorm.Config{})

	DB.AutoMigrate(&model.User{}, &model.Post{})

}
```

Este código establece la conexión a la base de datos y corre las migraciones para crear las tablas en la base de datos. Por defecto, creará las tablas `users` y `posts`.

La variable global llamada `DB *gorm.DB` almacenará la conexión a la base de datos. Al ser global, podremos importalo en otros ficheros.

## Relación One To Many

Abre el fichero `graph/model/post.go` y agrega la línea `` UserID int `json:"userId"` `` para establecer la relación one to many. Debe quedar así.

```go
package model

type Post struct {
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Text   string `json:"text"`
	User   *User  `json:"user"`
	UserID int    `json:"userId"`
}
```

Ahora abre el fichero `graph/model/user.go` y realiza la siguiente modificación para especificar que al actualizar o eliminar la entidad principal (User), las operaciones deben realizarse en cascada en los posts asociados en la base de datos. Debe quedar como sigue.

```go
package model

type User struct {
	ID       int     `json:"id"`
	Name     string  `json:"name"`
	Lastname string  `json:"lastname"`
	Posts    []*Post `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"posts"`
}
```

`gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`: Esta etiqueta se utiliza para especificar las restricciones de la base de datos para esta relación. En particular, indica que cuando se actualiza o elimina la entidad principal, se deben realizar operaciones en cascada en los posts asociados.

* `OnUpdate:CASCADE`: Indica que cuando la entidad principal se actualiza, las actualizaciones deben propagarse en cascada a los posts asociados.
    
* `OnDelete:CASCADE`: Indica que cuando la entidad principal se elimina, la eliminación debe propagarse en cascada a los posts asociados.
    

Esta etiqueta es importante porque si al intentar borrar un usuario, y este usuario tiene registros asociados en la tabla posts, se generará un error de integridad de datos, ya que los posts asociados no pueden quedar huérfanos. Al definir `OnDelete:CASCADE` indicamos que si el registro de usuario es borrado, deben borrarse de forma automática todos los registros asociados en la tabla posts.

Ahora abre el fichero `server.go` y agrega la llamada a la función para establecer la conexión y correr las migraciones.

```go
package main

import (
	"log"
	"net/http"
	"os"

	"github.com/99designs/gqlgen/graphql/handler"
	"github.com/99designs/gqlgen/graphql/playground"
	"github.com/alegrecode/graphql-api-users-posts/database"
	"github.com/alegrecode/graphql-api-users-posts/graph"
)

const defaultPort = "8080"

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = defaultPort
	}
    
    // Realiza la conexión a la BD y corre las migraciones
	database.Conexion()

	srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))

	http.Handle("/", playground.Handler("GraphQL playground", "/query"))
	http.Handle("/query", srv)

	log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
```

Ahora es un buen momento para probar si se realiza la conexión a la base de datos de forma correcta, y corren las migraciones de las tablas y se establece la relación "one to many" entre las tablas. Ejecuta el siguiente comando.

```plaintext
go run server.go
```

Si sale todo bien, al abrir su gestor de base de datos debe ver las tablas users y posts, con su correspondiente relación.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702075625557/b5332e04-76ea-4140-b3ce-b4787ac9f0d9.png align="center")

Ahora debemos empezar a crear las implementaciones en cada uno de los resolvers, pero primero debemos hacer que la conexión a la base de datos esté disponible en los resolvers. Para ello abre el fichero `graph/resolver.go` y añade un campo `DB *gorm.DB` .

```go
package graph

import "gorm.io/gorm"

type Resolver struct {
	DB *gorm.DB
}
```

Ahora abre el fichero `server.go` y le pasamos la conexión a la base de datos al resolver como sigue.

```go
srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{ 
		DB: database.DB, // Pasamos la conexión al resolver
	}}))
```

Ya tenemos todo listo para comenzar a crear las implementaciones.

## Crear un usuario

Para crear un nuevo usuario en la función `CreateUser` agrega el siguiente código.

```go
func (r *mutationResolver) CreateUser(ctx context.Context, user model.InputUser) (*model.User, error) {
	newUser := model.User{
		Name:     user.Name,
		Lastname: user.Lastname,
	}

	r.DB.Create(&newUser)
	return &newUser, nil
}
```

Este código representa la lógica para crear un nuevo usuario en la base de datos utilizando Gorm en respuesta a una mutación GraphQL. La estructura `InputUser` proporciona los datos necesarios para la creación del usuario, y el nuevo usuario creado se retorna como parte de la respuesta de la mutación.

Si ejecutas la aplicación, puedes probarlo de la siguiente manera.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702676692465/323c801b-aef6-4302-84d3-4a4723f6d11b.gif align="center")

## Actualizar un usuario

Para actualizar un usuario existente copia en la función `UpdateUser` el siguiente código.

```go
func (r *mutationResolver) UpdateUser(ctx context.Context, id int, user model.InputUser) (*model.User, error) {
	updatedUser := model.User{
		ID:       id,
		Name:     user.Name,
		Lastname: user.Lastname,
	}

	r.DB.Save(&updatedUser)
	return &updatedUser, nil
}
```

El ID del usuario y los nuevos valores se toman de los argumentos de la mutación, y el usuario actualizado se retorna como parte de la respuesta de la mutación.

Podemos probar actualizar un usuario como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702677508626/5002beea-a8d1-4acd-b67d-7b8eb37e765e.gif align="center")

Continuamos con la mutación para crear un nuevo post.

## Crear un nuevo post

Para crear un post nuevo, en la función `CreatePost` ingresa el siguiente código.

```go
func (r *mutationResolver) CreatePost(ctx context.Context, post model.InputPost) (*model.Post, error) {
	newPost := model.Post{
		Title:  post.Title,
		Text:   post.Text,
		UserID: post.UserID,
	}
	r.DB.Create(&newPost)
	return &newPost, nil
}
```

Se crea una nueva instancia del modelo `Post` (`newPost`). Los valores de la nueva publicación se toman de los campos de la estructura `InputPost` pasada como argumento.

Se asignan valores a los campos `Title`, `Text`, y `UserID` para establecer la relación con el ID del usuario.

Se utiliza el objeto `r.DB` para realizar la operación de creación en la base de datos. El puntero `&newPost` se pasa como argumento para indicar que se debe crear un nuevo registro en la base de datos con los valores proporcionados en `newPost`.

La publicación recién creada se retorna como parte de la respuesta de la mutación.

Podemos probarlo como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702758917281/3fec6f02-5f96-4215-8fad-973cbb2ca364.gif align="center")

Continuamos con la actualización de un post.

## Actualizar un post

Para actualizar un post, en la función `UpdatePost` añade el siguiente código.

```go
func (r *mutationResolver) UpdatePost(ctx context.Context, id int, post model.InputPost) (*model.Post, error) {
	updatedPost := model.Post{
		ID:     id,
		Title:  post.Title,
		Text:   post.Text,
		UserID: post.UserID,
	}

	r.DB.Save(&updatedPost)
	return &updatedPost, nil
}
```

Se crea una nueva instancia del modelo `Post` (`updatedPost`). Se asigna el ID de la publicación que se desea actualizar y se actualizan los campos `Title`, `Text`, y `UserID` con los valores proporcionados en la estructura `InputPost` pasada como argumento.

Se utiliza el objeto `r.DB` para realizar la operación de actualización en la base de datos. El puntero `&updatedPost` se pasa como argumento para indicar que se debe actualizar el registro en la base de datos con los nuevos valores proporcionados en `updatedPost`.

La publicación actualizada se retorna como parte de la respuesta de la mutación.

Lo probamos como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702760536594/0a8234dc-496a-4b58-8f83-1d3c655d53a8.gif align="center")

Seguimos con las consultas para obtener todo los usuarios y un usuario por su ID.

## Recuperar todos los usuarios

Para obtener todos lo usuarios de la base de datos, en la función `Users` añade el siguiente código.

```go
func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
	var users []*model.User
	r.DB.Preload("Posts").Find(&users)
	return users, nil
}
```

Se declara una variable llamada `users` que será una slice de punteros a objetos `model.User`. Esta slice almacenará los resultados de la consulta.

Se utiliza el objeto `r.DB` para realizar la operación de consulta en la base de datos. `Preload("Posts")` se utiliza para realizar la precarga de los posts asociados a cada usuario, evitando así la necesidad de realizar una consulta separada por cada usuario para obtener sus posts. `Find(&users)` ejecuta la consulta y almacena los resultados en la slice `users`.

Puedes probarlo como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702761159925/d1cf8b7b-f498-4a04-8da8-fd830e171390.gif align="center")

Recuperamos todos los usuarios y los post que están asociados a cada uno.

## Recuperar un usuario por su ID

Para obtener un usuario por su ID, en la función `User` agrega el siguiente código.

```go
func (r *queryResolver) User(ctx context.Context, id int) (*model.User, error) {
	user := model.User{}
	r.DB.Preload("Posts").First(&user, id)
	return &user, nil
}
```

Se declara una variable llamada `user` que será un objeto `model.User`. Esta variable almacenará el resultado de la consulta.

Se utiliza el objeto `r.DB` para realizar la operación de consulta en la base de datos. `Preload("Posts")` se utiliza para realizar la precarga de los posts asociados al usuario.

`First(&user, id)` ejecuta la consulta para obtener el primer usuario con el ID proporcionado y almacena el resultado en la variable `user`.

Se retorna un puntero al usuario `&user`, que contiene la información del usuario con sus posts precargados.

Probamos la consulta como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702761651198/b9ef7484-2f0a-4ba6-aa39-f236d88a15c5.gif align="center")

Recuperamos el usuario por su ID, y los posts que tiene asociados.

Seguimos con los posts.

## Recuperar todos los posts

Para obtener todos los posts, en la función `Posts` agrega el siguiente código.

```go
func (r *queryResolver) Posts(ctx context.Context) ([]*model.Post, error) {
	var posts []*model.Post
	r.DB.Preload("User").Find(&posts)
	return posts, nil
}
```

Se declara una variable llamada `posts` que será una slice de punteros a objetos [`model.Post`](http://model.Post). Esta slice almacenará los resultados de la consulta.

Se utiliza el objeto `r.DB` para realizar la operación de consulta en la base de datos. `Preload("User")` se utiliza para realizar la precarga de los usuarios asociados a cada post, evitando así la necesidad de realizar una consulta separada por cada publicación para obtener sus usuarios. `Find(&posts)` ejecuta la consulta y almacena los resultados en la slice `posts`.

Puedes probar la consulta como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702762265499/0a3b5c03-7a48-4526-a815-6aeca5b0514b.gif align="center")

Recuperamos todos los posts y al usuario al que pertenece.

## Recuperar un post por su ID

Para obtener un post por su ID, en la función `Post` agrega el siguiente código.

```go
func (r *queryResolver) Post(ctx context.Context, id int) (*model.Post, error) {
	post := model.Post{}
	r.DB.Preload("User").First(&post, id)
	return &post, nil
}
```

Se declara una variable llamada `post` que será un objeto [`model.Post`](http://model.Post). Esta variable almacenará el resultado de la consulta.

Se utiliza el objeto `r.DB` para realizar la operación de consulta en la base de datos. `Preload("User")` se utiliza para realizar la precarga del usuario asociado al post. `First(&post, id)` ejecuta la consulta para obtener el primera post con el ID proporcionado y almacena el resultado en la variable `post`.

Se retorna un puntero al post `&post`, que contiene la información del post con su usuario precargado.

Puedes probarlo como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702762884212/a75f1c2b-f987-4c8a-93e6-a1a4e467dc9c.gif align="center")

Recuperamos un post por su ID y el usuario asociado.

Continuamos con la eliminación de usarios y post.

## Eliminación de un post

Para borrar un post de la base de datos, en la función `DeletePost` agrega el siguiente código.

```go
func (r *mutationResolver) DeletePost(ctx context.Context, id int) (*model.Post, error) {
	deletedPost := model.Post{}
	r.DB.First(&deletedPost, id)
	r.DB.Delete(&deletedPost)
	return &deletedPost, nil
}
```

Se declara una variable llamada `deletedPost` que será un objeto [`model.Post`](http://model.Post). Esta variable se utilizará para almacenar el post que será eliminado.

Se utiliza el objeto `r.DB` para realizar la operación de consulta en la base de datos. `First(&deletedPost, id)` ejecuta la consulta para obtener el primer post con el ID proporcionado y almacena el resultado en la variable `deletedPost`.

Se utiliza el objeto `r.DB` nuevamente para realizar la operación de eliminación en la base de datos. `Delete(&deletedPost)` elimina el registro correspondiente al post almacenado en `deletedPost`.

Se retorna un puntero al post `&deletedPost`, que contiene la información del post que fue eliminado.

Puedes probarlo como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702763872528/f7f0565d-dd52-46f7-b8bd-c5f30874a72a.gif align="center")

Logramos borrar un registro de la tabla posts por medio de su ID.

## Eliminación de un usuario

Para borrar un usuario de la base de datos, en la función `DeleteUser` agrega el siguiente código.

```go
func (r *mutationResolver) DeleteUser(ctx context.Context, id int) (*model.User, error) {
	deletedUser := model.User{}
	r.DB.First(&deletedUser, id)
	r.DB.Delete(&deletedUser)
	return &deletedUser, nil
}
```

Se declara una variable llamada `deletedUser` que será un objeto `model.User`. Esta variable se utilizará para almacenar el usuario que será eliminado.

Se utiliza el objeto `r.DB` para realizar la operación de consulta en la base de datos. `First(&deletedUser, id)` ejecuta la consulta para obtener el primer usuario con el ID proporcionado y almacena el resultado en la variable `deletedUser`.

Se utiliza el objeto `r.DB` nuevamente para realizar la operación de eliminación en la base de datos. `Delete(&deletedUser)` elimina el registro correspondiente al usuario almacenado en `deletedUser`.

Se retorna un puntero al usuario `&deletedUser`, que contiene la información del usuario que fue eliminado.

Puedes probarlo como sigue.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1702764511109/8e56d192-bf37-440a-9f5f-680951f513b8.gif align="center")

Logramos borrar un registro de la tabla users por medio de su ID.

## Conclusión

En este tutorial, hemos explorado cómo construir una API GraphQL en Go utilizando gqlgen para definir el esquema GraphQL y Gorm para interactuar con una base de datos MySQL. A lo largo de este proceso, hemos cubierto los conceptos fundamentales de GraphQL, la configuración de modelos de datos con Gorm, y la implementación de operaciones CRUD para usuarios y publicaciones.

Algunos aspectos destacados de este tutorial incluyen la creación de modelos GraphQL con gqlgen, la implementación de resolvers para manejar operaciones CRUD, y la integración de Gorm para persistencia de datos. Además, hemos explorado la importancia de las etiquetas `gorm` para personalizar el mapeo de estructuras de Go a tablas de base de datos y para definir restricciones importantes.

Espero que este tutorial haya sido útil y te haya proporcionado una base sólida para construir aplicaciones GraphQL robustas en Go.

Puedes encontrar el proyecto completo en mi repositorio de GitHub haciendo clic [**AQUÍ**](https://github.com/AlegreCode/graphql-api-users-posts).

Espero que lo hayas encontrado entretenido, instructivo y claro. Si tienes alguna duda, puedes hacérmelo saber en los comentarios. Pronto estaré subiendo más tutoriales.

Nos vemos en la próxima. Saludos!👋😊
