# GraphQL

## Introducción

GraphQL es un lenguaje de consulta que te permite definir qué datos pedirle a un API. Se trata de una tecnología que Facebook empezó a desarrollar en 2012, aunque fue anunciada en 2015. Según Facebook, proporciona una descripción completa y comprensible de los datos de su API, ofrece a los clientes la posibilidad de pedir exactamente lo que necesitan, facilita la evolución de las API con el paso del tiempo (escalabilidad) y habilita potentes herramientas para desarrolladores.

## Uso

```javascript
// /graphql/index.js

// Dependencia que crea un servidor
const { ApolloServer } = require('@apollo/server')
// Playground incluido en @apollo/server
const { ApolloServerPluginLandingPageLocalDefault } = require('@apollo/server/plugin/landingPage/default')
// Middleware de Express también en @apollo/server
const { expressMiddleware } = require('@apollo/server/express4')

// Definición de tipos
const typeDefs = `
  type Query {
    hello: String
  }
`

// Resolvers
const resolvers = {
  Query: {
    hello: () => 'Hola mundillo'
  }
}

const useGraphQL = async (app) => {
  const server = new ApolloServer({
    typeDefs,
    resolvers,
    playground: true,
    plugins: [
      ApolloServerPluginLandingPageLocalDefault
    ]
  })

  await server.start()

// Uso del middleware en Express
  app.use(expressMiddleware(server,{
    context: async ({req}) => ({
      token: req.headers.token
    })
  }))
}

module.exports = useGraphQL
```

En el archivo que inicia el server

```javascript
// index.js

async function startServer() {
  try {    

    // cors
    const whitelist = [
      ...
      'http://localhost:3000'
    ];
    const corsOptions = {
      origin: (origin, callback) => {
        fLog('origin -' + origin);
        if (whitelist.indexOf(origin) !== -1 || !origin) {
          callback(null, true);
        } else {
          callback(new Error('Not allowed by CORS'));
        }
      },
    };
    app.use(cors(corsOptions));

    ...
    
    // GraphQL
    await useGraphQL(app);

    // API's
    routerApi(app);

    // middlewares
   ...

  } catch (err) {
    console.log(err);
    throw new Error('Internal server error', err);
  }
}
```

## typeDefs y los resolvers

En GraphQL, los `typeDefs` (definiciones de tipos) y los `resolvers` (resolutores) son dos conceptos fundamentales que trabajan juntos para definir y ejecutar consultas y mutaciones en una API de GraphQL.

### `typeDefs` (Definiciones de Tipos)

Los `typeDefs` definen la estructura del esquema de GraphQL. Incluyen tipos, consultas, mutaciones y sus respectivos campos. Es esencialmente el "contrato" que especifica qué operaciones están disponibles y qué datos se pueden consultar o modificar.

### `Resolvers` (Resolutores)

Los `resolvers` son funciones que proporcionan la lógica para obtener los datos definidos en los `typeDefs`. Cuando se realiza una consulta o mutación, los resolvers son los que realmente "resuelven" la solicitud, ejecutando la lógica necesaria para devolver los datos o realizar cambios.

#### Ejemplo&#x20;

**Definiendo el Esquema (`typeDefs`)**

```javascript
const typeDefs = gql`
  type User {
    id: ID!
    name: String
    email: String
  }

  type Query {
    getUser(id: ID!): User
    listUsers: [User]
  }

  type Mutation {
    createUser(name: String!, email: String!): User
    updateUser(id: ID!, name: String, email: String): User
    deleteUser(id: ID!): Boolean
  }
`;
```

*Nota: El type def de tipo Query es equivalente al GET y el Mutation es esquvalente al PUT, POST, DELETE y PATCH. El de tipo User no es propio de GraphQL, son propios, es decir, creados de manera personalizada.*

**Definiendo los Resolutores (`resolvers`)**

```javascript
const users = [];

const resolvers = {
  Query: {
    getUser: (parent, args) => users.find(user => user.id === args.id),
    listUsers: () => users,
  },
  Mutation: {
    createUser: (parent, args) => {
      const newUser = {
        id: String(users.length + 1),
        name: args.name,
        email: args.email,
      };
      users.push(newUser);
      return newUser;
    },
    updateUser: (parent, args) => {
      const user = users.find(user => user.id === args.id);
      if (user) {
        user.name = args.name || user.name;
        user.email = args.email || user.email;
        return user;
      }
      return null;
    },
    deleteUser: (parent, args) => {
      const index = users.findIndex(user => user.id === args.id);
      if (index !== -1) {
        users.splice(index, 1);
        return true;
      }
      return false;
    },
  },
};
```

En este ejemplo:

* `typeDefs` define los tipos `User`, las consultas `getUser` y `listUsers`, y las mutaciones `createUser`, `updateUser` y `deleteUser`.
* `resolvers` proporciona la lógica para manejar estas consultas y mutaciones, interactuando con una lista de usuarios en memoria (`users`).

## Consultas

En GraphQL todas las consultas son mediante POST accediendo al endpoint expuesto y toda petición retorna 201.

<figure><img src="https://624742151-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFRKN8coRWwuuSr24p99X%2Fuploads%2FVvjoElDg8K8mglKCCMsG%2Fimage.png?alt=media&#x26;token=ea629787-18d1-44d6-8d54-5d2cc0a8472b" alt=""><figcaption></figcaption></figure>

## Sistema de tipado

GraphQL viene con un conjunto de tipos escalares predeterminados listos para usar:

* **Int:** Un entero de 32 bits con signo.
* **Float:** Un valor de punto flotante de precisión doble con signo.
* **String:** Una secuencia de caracteres UTF‐8.
* **Boolean:** true o false.
* **ID:** El tipo escalar de ID representa un identificador único, que a menudo se usa para recuperar un objeto o como clave para un caché. El tipo de ID se serializa de la misma manera que una Cadena; sin embargo, definirlo como ID significa que no está destinado a ser legible por humanos.

## Nulabilidad y listas

En GraphQL, no define un nuevo tipo cuando intenta devolver una lista de elementos de un campo; simplemente aplica un modificador de lista a ese tipo, así:

```js
type ObjectType {
  singleRestaurant: Restaurant
  multipleRestaurants: [Restaurant]
}
```

Non-null también es un modificador, y resulta que puede aplicar modificadores de listas y no nulos de forma anidada arbitrariamente, especialmente porque las listas se pueden anidar:

```js
type ObjectType {
  first: Restaurant
  second: [Restaurant]
  third: [Restaurant!]
  fourth: [Restaurant!]!
  fifth: [[Restaurant!]]!
}
```

Entonces, ¿qué significa tener el no nulo dentro o fuera de una lista? Bueno, decide si el no nulo se aplica al elemento de la lista frente a la lista en sí.

Por ejemplo, puede tener una lista de cadenas no nulas:

```js
drinkSizes: [String!]
```

Esto significa que la lista en sí puede ser nula, pero no puede tener ningún miembro nulo. Por ejemplo, en JSON:

```js
drinkSizes: nulo // válido
drinkSizes: [] // válido
drinkSizes: ["pequeño", "grande"] // válido
drinkSizes: ["pequeño", nulo, "grande"] // error
```

Ahora, digamos que definimos una lista de cadenas no nulas:

```js
drinkSizes: [String]!
```

Esto significa que la lista en sí no puede ser nula, pero puede contener valores nulos:

```js
drinkSizes: nulo // error
drinkSizes: [] // válido
drinkSizes: ["pequeño", "grande"] // válido
drinkSizes: ["pequeño", nulo, "grande"] // válido
```

Finalmente, podemos combinar los dos:

```js
drinkSizes: [String!]!
```

Este es el más restrictivo:

```js
drinkSizes: nulo // error
drinkSizes: [] // válido
drinkSizes: ["pequeño", "grande"] // válido
drinkSizes: ["pequeño", nulo, "grande"] // error
```

Una conclusión interesante aquí es que no hay forma de especificar que la lista no puede estar vacía: una lista vacía \[ ] siempre es válida, independientemente de si la lista o los elementos no son nulos.

## Object types and fields

Tipos de objetos propios&#x20;

```javascript
type Book {
  title: String
  author: Author
}

type Author {
  name: String
  books: [Book]
}
```
