<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ api rest - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ api rest - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 19:37:29 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/tag/api-rest/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Documentando APIs REST en Node.js con Swagger Autogen y Swagger UI Express ]]>
                </title>
                <description>
                    <![CDATA[ La documentación de APIs REST es una tarea esencial para garantizar que otros desarrolladores puedan consumir y comprender el funcionamiento de nuestras APIs. Una buena documentación no solo es un signo de profesionalismo, sino también una herramienta poderosa para optimizar la colaboración y la eficiencia. Vamos a aprender a documentar ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/documentando-apis-rest-en-node-js-con-swagger-autogen-y-swagger-ui-express/</link>
                <guid isPermaLink="false">6755a38c96d716043ef3d6ad</guid>
                
                    <category>
                        <![CDATA[ api rest ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Leonardo José Castillo Lacruz ]]>
                </dc:creator>
                <pubDate>Tue, 10 Dec 2024 02:26:55 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/12/Youtube--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>La documentación de APIs REST es una tarea esencial para garantizar que otros desarrolladores puedan consumir y comprender el funcionamiento de nuestras APIs. Una buena documentación no solo es un signo de profesionalismo, sino también una herramienta poderosa para optimizar la colaboración y la eficiencia.</p><p>Vamos a aprender a documentar una API REST creada en Node.js utilizando las herramientas <strong>Swagger Autogen</strong> y <strong>Swagger UI Express</strong>. Además, exploraremos las ventajas que estas herramientas ofrecen para facilitar el desarrollo y el consumo de APIs.</p><hr><h3 id="-qu-es-swagger">¿Qué es Swagger?</h3><p><strong>Swagger</strong> es un conjunto de herramientas para definir y documentar APIs REST bajo el estándar OpenAPI. Es importante destacar que Swagger no está ligado a un lenguaje de programación específico, sino que su objetivo principal es describir de manera clara cómo interactuar con los servicios de una API. Con Swagger, es posible crear documentación interactiva que permite a los desarrolladores explorar y probar los endpoints directamente desde el navegador.</p><blockquote><strong>Nota:</strong> Aunque Swagger facilita la visualización y uso de la documentación, no genera automáticamente el archivo de especificación de la API. Este trabajo es realizado por herramientas como <strong>Swagger Autogen</strong>, que automatiza la creación de dicho archivo JSON o YAML.</blockquote><hr><h3 id="ventajas-de-usar-swagger-y-swagger-autogen">Ventajas de usar Swagger y Swagger Autogen</h3><ol><li><strong>Automatización del proceso de documentación</strong><br>Con <strong>Swagger Autogen</strong>, puedes generar el archivo de especificación a partir de tu código, reduciendo la carga manual y garantizando que siempre esté actualizado.</li><li><strong>Interfaz interactiva con Swagger UI Express</strong><br>La integración con <strong>Swagger UI Express</strong> permite visualizar y probar los endpoints de manera fácil y amigable.</li><li><strong>Estandarización y compatibilidad</strong><br>Al seguir el estándar OpenAPI, las APIs documentadas con Swagger son fácilmente entendibles por otros desarrolladores y herramientas.</li><li><strong>Reducción de Errores y Mejor Colaboración</strong><br>La sincronización entre código y documentación minimiza malentendidos y agiliza la colaboración entre equipos.</li><li><strong>Experiencia mejorada para consumidores</strong><br>Los desarrolladores que consumen tu API pueden integrarse más rápido gracias a la claridad y accesibilidad de la documentación.</li></ol><hr><h3 id="c-mo-documentar-tu-api-rest-con-swagger-autogen-y-swagger-ui-express">Cómo documentar tu API REST con Swagger Autogen y Swagger UI Express</h3><h4 id="1-preparaci-n-del-proyecto">1. <strong>Preparación del proyecto</strong></h4><p><strong>Inicia un proyecto Node.js</strong><br>Si aún no tienes un proyecto, inicialízalo con:</p><p><code>npm init -y</code></p><p><strong>Instala las dependencias necesarias</strong><br>Usa los siguientes comandos para instalar las herramientas requeridas:</p><p><code>npm install swagger-ui-express npm install --save-dev swagger-autogen</code></p><hr><h4 id="2-configuraci-n-de-swagger-autogen">2. <strong>Configuración de Swagger Autogen</strong></h4><p><strong>Crea el Archivo de Configuración</strong><br>Añade un archivo <code>swagger.js</code> en el directorio raíz con el siguiente contenido:</p><pre><code>const swaggerAutogen = require('swagger-autogen')();

const doc = {
    info: {
        title: 'API de Mascotas',
        description: 'Documentación de la API para la gestión de mascotas',
    },
    host: 'localhost:3000',
    schemes: ['http'],
};

const outputFile = './swagger_output.json';
const endpointsFiles = ['./index.js']; // Cambia este archivo según el punto de entrada de tu API

swaggerAutogen(outputFile, endpointsFiles).then(() =&gt; {
    require('./index'); // Inicia el servidor automáticamente
});
</code></pre><p>En el script anterior, importamos el paquete swagger-autogen y definimos las configuraciones necesarias para realizar la construcción del archivo .json necesario para mostrar la documentación.</p><p><strong>Ejecuta el script de generación</strong><br>Ejecuta el siguiente comando para generar el archivo JSON de especificación:bashCopiar código<code>node swagger.js</code></p><p>Esto creará un archivo llamado <code>swagger_output.json</code> que contiene la descripción de los endpoints de tu API. Este archivo será usado por el paquete swagger-ui-express.</p><hr><h4 id="3-integraci-n-con-swagger-ui-express">3. <strong>Integración con Swagger UI Express</strong></h4><p><strong>Configura la ruta de documentación</strong><br>Modifica el archivo principal de tu API (<code>index.js</code>) para incluir el middleware de Swagger UI Express:</p><pre><code>const express = require('express');
const swaggerUi = require('swagger-ui-express');
const swaggerFile = require('./swagger_output.json');

const app = express();

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerFile));

app.listen(3000, () =&gt; {
    console.log('Servidor corriendo en http://localhost:3000');
});
</code></pre><ol><li><strong>Accede a la documentación</strong><br>Inicia tu servidor y abre un navegador en <code>http://localhost:3000/api-docs</code> para explorar los endpoints de tu API a través de la interfaz interactiva.</li></ol><hr><p>Swagger Autogen, hace una lectura del código, luego lo verifica y a partir del él va a generar todo lo necesario. </p><p>Importante cuando uses métodos que requieren o usan el payload (req.body) haz la desestructuración que swagger autogen, va a incluir esta definición en la llamada o uso del endpoint respectivo.</p><p>Si deseas personalizar o complementar la documentación, puedes agregar comentarios en el controller de forma que swagger autogen los tome en cuenta. &nbsp;</p><h3 id="ejemplo-de-c-digo-documentado">Ejemplo de código documentado</h3><p>El uso de comentarios en tus controladores puede mejorar la documentación generada. Por ejemplo:</p><pre><code>/**
 * @route GET /pets
 * @description Obtiene una lista de mascotas
 * @response 200 - Lista de mascotas
 */
app.get('/pets', (req, res) =&gt; {
    res.send([{ id: 1, name: 'Fido' }, { id: 2, name: 'Luna' }]);
});
</code></pre><p>Swagger Autogen extraerá estos comentarios para enriquecer la especificación de tu API.</p><hr><p>El uso de <strong>Swagger Autogen</strong> y <strong>Swagger UI Express</strong> transforma la documentación de APIs REST en un proceso eficiente y profesional. Estas herramientas no solo automatizan tareas tediosas, sino que también proporcionan una experiencia superior para los consumidores de la API, quienes pueden explorar y probar los servicios de manera intuitiva.</p><p>Implementar Swagger en tus proyectos garantiza una documentación clara, estandarizada y accesible, facilitando la colaboración entre equipos y mejorando la percepción de calidad de tu API.</p><p>En este contenido, realizamos la implementación de la documentación de una API real, donde hacemos el paso a paso y obtenemos el swagger a partir de la ejecución de lo descrito anteriormente.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/3EMLqQ6ny80?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Aprende a Documentar tu API Node.js con Swagger Autogen y Swagger UI Express 🚀" name="fitvid0"></iframe>
          </div>
        </div>
      </figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo consumir REST APIs en React: Guía para principiantes ]]>
                </title>
                <description>
                    <![CDATA[ React es una librería popular de Front-end que los desarrolladores usan para crear aplicaciones. Si quieres crear aplicaciones listas para poner en producción seguramente vas a necesitar saber integrar APIs a tu aplicación de React en algún momento de tu carrera. Cada desarrollador que quiera construir aplicaciones web robustas y ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-consumir-rest-apis-en-react-guia-para-principiantes/</link>
                <guid isPermaLink="false">6565bacab9adab03e4e55c21</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ api rest ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Constanza Areal ]]>
                </dc:creator>
                <pubDate>Wed, 17 Jan 2024 18:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/01/cover-template-2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-consume-rest-apis-in-react/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Consume REST APIs in React – a Beginner's Guide</a>
      </p><p>React es una librería popular de Front-end que los desarrolladores usan para crear aplicaciones. Si quieres crear aplicaciones listas para poner en producción seguramente vas a necesitar saber integrar APIs a tu aplicación de React en algún momento de tu carrera.</p><p>Cada desarrollador que quiera construir aplicaciones web robustas y modernas con React tiene que saber cómo consumir APIs para traer información a su aplicación de React.</p><p>En esta guía para principiantes, vamos a aprender como consumir una API RESTful en React trayendo, borrando o agregando información. &nbsp;También veremos dos formas de consumir APIs RESTful y cómo usarla con React Hooks.</p><h3 id="aqu-tienes-un-scrim-interactivo-sobre-c-mo-consumir-apis-rest-en-react-"><strong>Aquí tienes un scrim interactivo sobre cómo consumir APIs REST en React:</strong></h3><figure class="kg-card kg-embed-card"><iframe src="https://scrimba.com/scrim/coc6f42838bab19b28a86cca1?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-weight: 400; font-stretch: inherit; line-height: inherit; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: middle; color: rgb(10, 10, 35); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"></iframe></figure><h2 id="-qu-es-una-api-rest"><strong>¿Qué es una API REST?</strong></h2><p> Si alguna vez haz pasado tiempo programando o investigando sobre programación, seguramente te haz cruzado con el término "API".</p><p>API significa "Interfaz de Programación de Aplicación", por sus siglas en inglés. Es un medio que permite la comunicación programática entre diferentes aplicaciones y que devuelve una respuesta en tiempo real.</p><p>En los 2000, Roy Fielding definió el concepto REST como un estilo de arquitectura y metodología usado frecuentemente en el desarrollo de servicios de internet, como, por ejemplo, los sistemas de hipermedia distribuidos. Es un acrónimo que significa, en inglés, Transferencia de Estado Representacional.</p><p>Cuando se hace una petición a través de una API REST, ésta envía, al peticionante o a un endpoint, una representación del estado actual del recurso. Esta representación del estado puede tomar la forma de archivo JSON (JavaScript Object Notation), XML, o HTML.</p><p>JSON es el formato de archivo más usado porque no depende de ningún lenguaje de programación y puede ser leído tanto por personas como por computadoras.</p><p><strong>Por ejemplo:</strong></p><pre><code class="language-json">[
   {
      "userId": 1,
      "id": 1,
      "title": "sunt excepturi",
      "body": "quia et suscipit\nsuscipit recusandae consequuntur "
   },
   {
      "userId": 1,
      "id": 2,
      "title": "qui est esse",
      "body": "est rerum tempore vitae\nsequi sint nihil"
   }
]</code></pre><h2 id="c-mo-consumir-apis-rest-en-react"><strong>Cómo consumir APIs REST en React</strong></h2><p>Es posible consumir APIs REST dentro de una aplicación React de distintas maneras, pero en esta guía veremos dos de las formas más populares: Axios (un cliente HTTP basado en promesas) y Fetch API (una API web ya incluida en el navegador).</p><p><strong><strong>Not</strong>a<strong>:</strong></strong> Para poder comprender esta guía en su totalidad, deberías saber JavaScript, React y React Hooks, ya que son conocimientos que vamos a usar aquí.</p><p>Antes de explicar cómo consumir APIs, es importante entender que consumir APIs en React es muy diferente de como se lo hace en JavaScript. Esto es porque estas peticiones ahora se hacen en un componente de React.</p><p>En nuestro caso, vamos a usar componentes funcionales, lo que significa que vamos a necesitar 2 Hooks de React importantes:</p><ul><li><strong>Hook <strong>useEffect:</strong></strong> En React, las peticiones a las API se hacen dentro del hook <code>useEffect()</code>. El hook muestra la información cuando la aplicación es montada o después de se alcanza un estado específico. Esta es la sintaxis general que vamos a usar:</li></ul><pre><code>useEffect(() =&gt; {
    // data fetching here
}, []);
</code></pre><ul><li><strong>Hook <strong>useState:</strong></strong> Al pedir información, debemos crear un estado en el cual se va a guardar el resultado de la petición. También lo podemos guardar en un herramienta de administración de estado como Redux o en un objeto de contexto. Para hacerlo más simple, vamos a guardar el resultado de la petición en el estado local de React.</li></ul><pre><code>const [posts, setPosts] = useState([]);
</code></pre><p>Vamos a meternos en la parte jugosa de esta guía, donde aprenderemos como obtener, agregar, y borrar información usando la API <a href="https://jsonplaceholder.typicode.com/posts">JSONPlaceholder</a>. Este conocimiento es aplicable a cualquier tipo de API, ya que esta guía está orientada a principiantes.</p><h2 id="c-mo-consumir-apis-con-la-fetch-api"><strong>Cómo consumir APIs con la Fetch API</strong></h2><p>La Fetch API es un método JavaScript para obtener recursos de un servidor o de un endpoint de una API. Como ya viene incluida en el navegador, no es necesario instalar dependencias o paquetes.</p><p>El método <code>fetch()</code> requiere de un argumento obligatorio que es la URL o dirección al recurso que queremos obtener. Luego, este se convierte en una promesa para que podamos manejar su éxito o error a través de los métodos <code>then()</code> y <code>catch()</code>.</p><p>Una petición fetch básica es muy simple de escribir y se parece al código de abajo. Lo que estamos haciendo es simplemente obtener información desde una URL que devuelve esa información como un JSON y luego mostrándola en la consola:</p><pre><code class="language-js">fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
   .then(response =&gt; response.json())
   .then(data =&gt; console.log(data));
</code></pre><p>La respuesta por defecto es una respuesta HTTP estándar más que un JSON, pero podemos ver la información como un objeto JSON al usar el método json() incluida en la respuesta.</p><h3 id="c-mo-realizar-una-petici-n-get-en-react-con-fetch-api"><strong>Cómo realizar una petición GET en React con Fetch API</strong></h3><p>Es posible usar el método HTTP GET para obtener información desde un endpoint.</p><p>Como dijimos antes, Fetch API solo acepta un argumento obligatorio, lo cual es cierto. También acepta un argumento option, el cual es opcional, específicamente cuando se usa el método GET, el cual es el método predeterminado. Pero para los otros métodos como POST y DELETE, es necesario usar el método con un arreglo:</p><pre><code class="language-js">fetch(url, {
    method: "GET" // default, so we can ignore
})
</code></pre><p>Hasta el momento aprendimos cómo funcionan las cosas, ahora vamos a poner todo lo que aprendimos junto y hacer una petición get para obtener información de nuestra API.</p><p>De nuevo, volvemos a usar la<a href="https://jsonplaceholder.typicode.com/posts"> API gratuita JSONPlaceholder</a> para obtener una lista de posts dentro de nuestra aplicación:</p><pre><code class="language-js">import React, { useState, useEffect } from 'react';

const App = () =&gt; {
   const [posts, setPosts] = useState([]);
   useEffect(() =&gt; {
      fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
         .then((response) =&gt; response.json())
         .then((data) =&gt; {
            console.log(data);
            setPosts(data);
         })
         .catch((err) =&gt; {
            console.log(err.message);
         });
   }, []);

return (
   // ... consume here
);
};
</code></pre><p>Creamos un estado en el código anterior para guardar la información que obtuvimos de la API así la podemos usar después en nuestra aplicación. También podemos establecer el valor predeterminado a un arreglo vacío.</p><pre><code class="language-js">const [posts, setPosts] = useState([]);
</code></pre><p>Como la parte más importante de <code>then()</code> ocurrió en el hook useState, la información/los posteos se obtienen apenas carga la aplicación. La petición fetch produce una promesa que puede ser aceptada o rechazada:</p><pre><code class="language-js">useEffect(() =&gt; {
   fetch('https://jsonplaceholder.typicode.com/posts?_limit=10').then(
      (response) =&gt; console.log(response)
   );
}, []);
</code></pre><p>Esta respuesta contiene una gran cantidad de información, como el código de estado, texto, y otra información que vamos a necesitar después para manejar los errores. </p><p>Hasta ahora, hemos manejado la resolución de una promesa con <code>.then()</code>, pero nos devolvió un objeto como respuesta que no es lo que queremos. Por esos, necesitamos transformar el objeto respuesta al formato JSON con el método <code>.then()</code>. Esto también nos devuelve una promesa para que podamos obtener la información usando el segundo <code>.then()</code>.</p><pre><code class="language-js">useEffect(() =&gt; {
   fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
      .then((response) =&gt; response.json())
      .then((data) =&gt; {
         console.log(data);
         setPosts(data);
      });
}, []);
</code></pre><p>Si miramos la consola, vamos a ver que obtuvimos 10 posts de nuestra API, lo que también especificamos anteriormente en el estado.</p><p>Esto no está completo porque solamente estuvimos manejando la resolución favorable de la promesa pero no su rechazo, lo cual haremos con el método <code>.catch()</code>:</p><pre><code class="language-js">useEffect(() =&gt; {
   fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
      .then((response) =&gt; response.json())
      .then((data) =&gt; {
         console.log(data);
         setPosts(data);
      })
      .catch((err) =&gt; {
         console.log(err.message);
      });
}, []);
</code></pre><p>Hasta ahora vimos como hacer una petición <code>GET</code>. Esta puede ser consumida dentro de nuestra aplicación, a través de un bucle que recorra nuestro arreglo:</p><pre><code class="language-js">const App = () =&gt; {
// ...

   return (
   &lt;div className="posts-container"&gt;
      {posts.map((post) =&gt; {
         return (
            &lt;div className="post-card" key={post.id}&gt;
               &lt;h2 className="post-title"&gt;{post.title}&lt;/h2&gt;
               &lt;p className="post-body"&gt;{post.body}&lt;/p&gt;
               &lt;div className="button"&gt;
               &lt;div className="delete-btn"&gt;Delete&lt;/div&gt;
               &lt;/div&gt;
            &lt;/div&gt;
         );
      })}
   &lt;/div&gt;
   );
};

export default App;
</code></pre><h3 id="c-mo-realizar-una-petici-n-post-en-react-con-fetch-api"><strong>Cómo realizar una petición POST en React con Fetch API</strong></h3><p>Es posible usar el método HTTP <code>POST</code> para enviar información a un endpoint. Funciona de manera similar a la petición <code>GET</code>, la única diferencia está en que es necesario agregar el método y dos parámetros adicionales al objeto opcional:</p><pre><code class="language-js">const addPosts = async (title, body) =&gt; {
await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
   title: title,
   body: body,
   userId: Math.random().toString(36).slice(2),
}),
headers: {
   'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) =&gt; response.json())
.then((data) =&gt; {
   setPosts((posts) =&gt; [data, ...posts]);
   setTitle('');
   setBody('');
})
.catch((err) =&gt; {
   console.log(err.message);
});
};
</code></pre><p>Los dos parámetros que pueden parecer extraños son el body (cuerpo) y el header (encabezado).</p><p>En el body va a estar toda la información que queremos enviar a la API, la cual primero debemos convertir en una cadena de texto porque estamos enviando información al navegador. El header nos dice el tipo de información, que es siempre el mismo cuando consumimos APIs REST. También creamos el estado que va a guardar ésta nueva información y distribuir la información restante por el arreglo.</p><p>Si miramos el método <code>addPost()</code> que creamos, va a necesitar que esa información venga de un formulario o de otro lado. En nuestro caso, hice un formulario, obtuve la información mediante estados. Al enviar el formulario, la información es incluida en el método:</p><pre><code class="language-js">import React, { useState, useEffect } from 'react';
const App = () =&gt; {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
// ...
const addPosts = async (title, body) =&gt; {
   await fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'POST',
      body: JSON.stringify({
         title: title,
         body: body,
         userId: Math.random().toString(36).slice(2),
      }),
      headers: {
         'Content-type': 'application/json; charset=UTF-8',
      },
   })
      .then((response) =&gt; response.json())
      .then((data) =&gt; {
         setPosts((posts) =&gt; [data, ...posts]);
         setTitle('');
         setBody('');
      })
      .catch((err) =&gt; {
         console.log(err.message);
      });
};

const handleSubmit = (e) =&gt; {
   e.preventDefault();
   addPosts(title, body);
};    

return (
   &lt;div className="app"&gt;
      &lt;div className="add-post-container"&gt;
         &lt;form onSubmit={handleSubmit}&gt;
            &lt;input type="text" className="form-control" value={title}
               onChange={(e) =&gt; setTitle(e.target.value)}
            /&gt;
            &lt;textarea name="" className="form-control" id="" cols="10" rows="8" 
               value={body} onChange={(e) =&gt; setBody(e.target.value)} 
            &gt;&lt;/textarea&gt;
            &lt;button type="submit"&gt;Add Post&lt;/button&gt;
         &lt;/form&gt;
      &lt;/div&gt;
      {/* ... */}
   &lt;/div&gt;
);
};

export default App;
</code></pre><h3 id="c-mo-realizar-una-petici-n-delete-en-react-con-fetch-api"><strong>Cómo realizar una petición DELETE en React con Fetch API</strong></h3><p>Es posible usar el método HTTP <code>DELETE</code> para eliminar información de un endpoint. También funciona de forma similar a la petición <code>GET</code>, la principal diferencia radica en que tenemos que agregar el método:</p><pre><code class="language-js">const deletePost = async (id) =&gt; {
await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
   method: 'DELETE',
}).then((response) =&gt; {
   if (response.status === 200) {
      setPosts(
         posts.filter((post) =&gt; {
            return post.id !== id;
         })
      );
   } else {
      return;
   }
});
};
</code></pre><p>Este código se dispara al hacer click en el botón. De esta manera, obtenemos el id del post específico en el cual se hizo click. </p><p>Este método hace que se elimine la información del resultado devuelto. Esto permite que la información sea borrada de la API, pero no inmediatamente de la UI y por eso necesitamos agregar un filtro que elimine la información también de ahí. Para cada ítem del bucle, tú botón de borrar debería lucir así:</p><pre><code class="language-js">const App = () =&gt; {
// ...

   return (
   &lt;div className="posts-container"&gt;
      {posts.map((post) =&gt; {
         return (
            &lt;div className="post-card" key={post.id}&gt;
               {/* ... */}
               &lt;div className="button"&gt;
                  &lt;div className="delete-btn" onClick={() =&gt; deletePost(post.id)}&gt;
                     Delete
                  &lt;/div&gt;
               &lt;/div&gt;    
            &lt;/div&gt;
         );
      })}
   &lt;/div&gt;
   );
};

export default App;
</code></pre><h3 id="c-mo-usar-async-await-en-fetch-api"><strong>Cómo usar Async/Await en Fetch API</strong></h3><p>Hasta ahora vimos como hacer peticiones fetch usando la sintaxis de las promesas, que puede ser confusa a veces. Y después, el encadenamiento con <code>.then()</code>. Podemos evitar el encadenamiento usando Async/await y así escribir código más legible.</p><p>Para usar async/awaiy, primero hay que escribir <code>async</code> en la función. Después, al hacer una petición y esperar un respuesta, hay que agregar la sintaxis <code>await</code> delante de la función para esperar a que la promesa devuelva el resultado.</p><p>Cuando usamos async/await, todas las peticiones Fetch se ven así:</p><pre><code class="language-js">import React, { useState, useEffect } from 'react';

const App = () =&gt; {
   const [title, setTitle] = useState('');
   const [body, setBody] = useState('');
   const [posts, setPosts] = useState([]);

   // GET with fetch API
   useEffect(() =&gt; {
      const fetchPost = async () =&gt; {
         const response = await fetch(
            'https://jsonplaceholder.typicode.com/posts?_limit=10'
         );
         const data = await response.json();
         console.log(data);
         setPosts(data);
      };
      fetchPost();
   }, []);

   // Delete with fetchAPI
   const deletePost = async (id) =&gt; {
      let response = await fetch(
         `https://jsonplaceholder.typicode.com/posts/${id}`,
         {
            method: 'DELETE',
         }
      );
      if (response.status === 200) {
         setPosts(
            posts.filter((post) =&gt; {
               return post.id !== id;
            })
         );
      } else {
         return;
      }
   };

   // Post with fetchAPI
   const addPosts = async (title, body) =&gt; {
      let response = await fetch('https://jsonplaceholder.typicode.com/posts', {
         method: 'POST',
         body: JSON.stringify({
            title: title,
            body: body,
            userId: Math.random().toString(36).slice(2),
         }),
         headers: {
            'Content-type': 'application/json; charset=UTF-8',
         },
      });
      let data = await response.json();
      setPosts((posts) =&gt; [data, ...posts]);
      setTitle('');
      setBody('');
   };

   const handleSubmit = (e) =&gt; {
      e.preventDefault();
      addPosts(title, body);
   };

   return (
      // ...
   );
};

export default App;
</code></pre><h4 id="aqu-tienes-un-scrim-interactivo-para-guiarte-"><strong>Aquí tienes un scrim interactivo para guiarte:</strong></h4><figure class="kg-card kg-embed-card"><iframe src="https://scrimba.com/scrim/co1af4d8f8db412c467e20af0?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-weight: 400; font-stretch: inherit; line-height: inherit; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: middle; color: rgb(10, 10, 35); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"></iframe></figure><h3 id="c-mo-manejar-errores-con-fetch-api"><strong>Cómo manejar errores con Fetch API</strong></h3><p>En esta sección, vamos a ver como manejar error de manera tradicional y con async/await.</p><p>Para manejar los errores con Fetch API, podemos usar la misma información de la respuesta o usar la sentencia try/catch si usamos async/await. </p><p>Primero veamos cómo podemos hacerlo con Fetch API:</p><pre><code class="language-js">const fetchPost = () =&gt; {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
   .then((response) =&gt; {
      if (!response.ok) {
         throw Error(response.statusText);
      }
      return response.json();
   })
   .then((data) =&gt; {
      console.log(data);
      setPosts(data);
   })
   .catch((err) =&gt; {
      console.log(err.message);
   });
};
</code></pre><p><a href="https://www.tjvantoll.com/2015/09/13/fetch-and-errors/">Aquí </a>(en inglés) puedes leer más sobre errores en Fetch API.</p><p>Para async/await podemos usar &nbsp;<code>try</code> y <code>catch</code> de esta forma:</p><pre><code class="language-js">const fetchPost = async () =&gt; {
   try {
      const response = await fetch(
         'https://jsonplaceholder.typicode.com/posts?_limit=10'
      );
      const data = await response.json();
      setPosts(data);
   } catch (error) {
      console.log(error);
   }
};
</code></pre><h2 id="c-mo-consumir-apis-con-axios-"><strong>Cómo consumir APIs con Axios:</strong></h2><p>Axios es un &nbsp;cliente HTTP basado en promesas que hace más simple el envío de peticiones HTTP asíncronas a endpoints REST. El endpoint en nuestro caso la API de posts de JSONPlaceholder, a la cual haremos peticiones &nbsp;<code>GET</code>, <code>POST</code>, y <code>DELETE</code>.</p><h4 id="aqu-tienes-un-scrim-interactivo-que-te-guiar-por-los-distintos-pasos-mientras-lees-"><strong>Aquí tienes un scrim interactivo que te guiará por los distintos pasos mientras lees:</strong></h4><figure class="kg-card kg-embed-card"><iframe src="https://scrimba.com/scrim/cob6540b4a1ad315f83abd56d?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-weight: 400; font-stretch: inherit; line-height: inherit; font-family: Lato, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: middle; color: rgb(10, 10, 35); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"></iframe></figure><h3 id="c-mo-instalar-y-configurar-axios"><strong>Cómo instalar y configurar Axios</strong></h3><p>A diferencia de Fetch API, Axios no viene incluido en el navegador por lo que necesitamos instalarlo en nuestro proyecto para poder utilizarlo.</p><p>Para poder instalar Axios en tu proyecto necesitas correr el siguiente comando:</p><pre><code class="language-bash">npm install axios
</code></pre><p>Una vez que lo instalamos correctamente, podemos crear una instancia, lo cual es opcional pero recomendable ya que nos evita repeticiones innecesarias.</p><p>Para crear una instancia, usamos el método <code>.create()</code>, que podemos usarlo para especificar información como la URL y posibles encabezados:</p><pre><code class="language-js">import axios from "axios";

const client = axios.create({
   baseURL: "https://jsonplaceholder.typicode.com/posts" 
});
</code></pre><h3 id="c-mo-realizar-una-petici-n-get-en-react-con-axios"><strong>Cómo realizar una petición GET en React con Axios</strong></h3><p>Usaremos la instancia que creamos anterior para realizar la petición GET. Todo lo que necesitamos es establecer parámetros, si los hay, y obtener la respuesta como un JSON por defecto.</p><p>A diferencia del método Fetch API, no se necesita una option para declarar el método. Solamente agregamos el método a la instancia y hacemos la petición.</p><pre><code class="language-js">useEffect(() =&gt; {
   client.get('?_limit=10').then((response) =&gt; {
      setPosts(response.data);
   });
}, []);
</code></pre><h3 id="c-mo-hacer-una-petici-n-post-en-react-con-axios"><strong>Cómo hacer una petición POST en React con Axios</strong></h3><p>Como dijimos antes, se puede usar el método <code>POST</code> para enviar información a un endpoint. Funciona de manera similar a la petición &nbsp;<code>GET</code>, siendo la principal diferencia el requesito de incluir el método y una option para guardar la información que estamos enviando:</p><pre><code class="language-js">const addPosts = (title, body) =&gt; {
   client
      .post('', {
         title: title,
         body: body,
      })
      .then((response) =&gt; {
         setPosts((posts) =&gt; [response.data, ...posts]);
      });
};
</code></pre><h3 id="c-mo-hacer-una-petici-n-delete-en-react-con-axios"><strong>Cómo hacer una petición DELETE en React con Axios</strong></h3><p>Podemos hacer peticiones delete con el método delete, el cual obtiene el <code>id</code> &nbsp;y lo borra de la API. También usaremos el método filter para borrarlo de la UI, como lo hicimos con el método Fetch API:</p><pre><code class="language-js">const deletePost = (id) =&gt; {
   client.delete(`${id}`);
   setPosts(
      posts.filter((post) =&gt; {
         return post.id !== id;
      })
   );
};
</code></pre><h3 id="c-mo-usar-async-await-en-axios"><strong>Cómo usar Async/Await en Axios</strong></h3><p>Hasta ahora hemos visto con hacer peticiones con Axios usando la sintaxis para promesas. Pero ahora veamos cómo usar async/await para escribir menos código y evitar el encadenamiento con <code>.then()</code></p><p>Cuando usemos async/await, todas nuestras peticiones Axios se verán así:</p><pre><code class="language-js">import React, { useState, useEffect } from 'react';

const App = () =&gt; {
   const [title, setTitle] = useState('');
   const [body, setBody] = useState('');
   const [posts, setPosts] = useState([]);

   // GET with Axios
   useEffect(() =&gt; {
      const fetchPost = async () =&gt; {
         let response = await client.get('?_limit=10');
         setPosts(response.data);
      };
      fetchPost();
   }, []);

   // Delete with Axios
   const deletePost = async (id) =&gt; {
      await client.delete(`${id}`);
      setPosts(
         posts.filter((post) =&gt; {
            return post.id !== id;
         })
      );
   };

   // Post with Axios
   const addPosts = async (title, body) =&gt; {
      let response = await client.post('', {
         title: title,
         body: body,
      });
      setPosts((posts) =&gt; [response.data, ...posts]);
   };

   const handleSubmit = (e) =&gt; {
      e.preventDefault();
      addPosts(title, body);
   };

   return (
      // ...
   );
};

export default App;
</code></pre><h3 id="c-mo-manejar-errores-con-axios"><strong>Cómo manejar errores con Axios</strong></h3><p>Para peticiones con Axios basadas en promesas, podemos usar los métodos <code>.then()</code> y .<code>catch (</code>) , pero para async/awit, podemos usar el bloque <code>try...catch</code>. Esto es muy similar a como lo implementamos en Fetch API. <br>El bloque <code>try...catch</code> se verá así:</p><pre><code class="language-js">const fetchPost = async () =&gt; {
   try {
      let response = await client.get('?_limit=10');
      setPosts(response.data);
   } catch (error) {
      console.log(error);
   }
};
</code></pre><p><a href="https://stackabuse.com/handling-errors-with-axios/">Aquí </a>(en inglés) puedes leer más sobre como manejar errores en Axios.</p><h2 id="fetch-api-vs-axios"><strong>Fetch API vs Axios</strong></h2><p>Quizás hayas notado algunas diferencias, pero vamos a ponerlas en un tabla así podemos comparar Fetch y Axios. </p><p>Estas distinciones le ayudarán a decidir qué método utilizar para un proyecto concreto. Entre estas distinciones se encuentran:</p><!--kg-card-begin: html--><table style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-alternates: inherit; font-variant-position: inherit; font-weight: 400; font-stretch: inherit; line-height: inherit; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Ubuntu, Cantarell, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.6rem; vertical-align: top; border-spacing: 0px; border-collapse: collapse; display: inline-block; overflow-x: auto; max-width: 100%; width: auto; white-space: nowrap; background: radial-gradient(at left center, rgba(0, 0, 0, 0.2) 0px, rgba(0, 0, 0, 0) 75%) 0px center / 10px 100% no-repeat scroll, radial-gradient(at right center, rgba(0, 0, 0, 0.2) 0px, rgba(0, 0, 0, 0) 75%) 100% center / 10px 100% scroll rgb(255, 255, 255); color: rgb(10, 10, 35); letter-spacing: normal; orphans: 2; text-align: start; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><thead style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><th style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.2rem; vertical-align: baseline; color: var(--gray85); letter-spacing: 0.2px; text-align: left; text-transform: uppercase; background: var(--body-bg);">AXIOS</th><th style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 1.2rem; vertical-align: baseline; color: var(--gray85); letter-spacing: 0.2px; text-align: left; text-transform: uppercase; background: var(--body-bg);">FETCH</th></tr></thead><tbody style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to right, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-size: 20px 100%; background-repeat: no-repeat;">Axios is a standalone third-party package that is simple to install.</td><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to left, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat;">Fetch is built into most modern browsers.<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">No installation</strong><span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span>is required as such.</td></tr><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to right, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-size: 20px 100%; background-repeat: no-repeat;">Axios uses the<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">data</strong><span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span>property.</td><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to left, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat;">Fetch uses the<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">body</strong><span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span>property.</td></tr><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to right, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-size: 20px 100%; background-repeat: no-repeat;">Axios data contains the<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">object</strong>.</td><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to left, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat;">Fetch’s body has to be<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">stringified</strong>.</td></tr><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to right, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-size: 20px 100%; background-repeat: no-repeat;">When the status is 200 and the statusText is 'OK,' the Axios request is accepted.</td><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to left, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat;">Fetch request is ok when<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">response object contains the ok property</strong>.</td></tr><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to right, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-size: 20px 100%; background-repeat: no-repeat;">Axios performs<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">automatic transforms of JSON data</strong>.</td><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to left, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat;">Fetch is a<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">two-step process</strong><span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span>when handling JSON data- first, to make the actual request; second, to call the .json() method on the response.</td></tr><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to right, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-size: 20px 100%; background-repeat: no-repeat;">Axios allows<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">cancelling request and request timeout</strong>.</td><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to left, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat;">Fetch does not.</td></tr><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to right, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-size: 20px 100%; background-repeat: no-repeat;">Axios has<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">built-in support for download progress</strong>.</td><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to left, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat;">Fetch does not support upload progress.</td></tr><tr style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;"><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to right, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-size: 20px 100%; background-repeat: no-repeat;">Axios has<span style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline;">&nbsp;</span><strong style="box-sizing: border-box; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: bolder; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; color: var(--gray85);">wide browser support</strong>.</td><td style="box-sizing: border-box; margin: 0px; padding: var(--su-2); border: 1px solid var(--base-20); font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 16px; vertical-align: baseline; background-image: linear-gradient(to left, rgb(255, 255, 255) 50%, rgba(255, 255, 255, 0) 100%); background-position: 100% 0px; background-size: 20px 100%; background-repeat: no-repeat;">Fetch is only compatible with Chrome 42+, Firefox 39+, Edge 14+, and Safari 10.1+. (This is known as Backward Compatibility).</td></tr></tbody></table><!--kg-card-end: html--><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>En esta guía aprendimos a consumir APIs REST en React con Fetch API y Axios.</p><p>Esto te ayudará a empezar a consumir API en React, y desde ahí podrás consumir información de manera más complejas y manipular APIs de la manera que quieras.</p><p>¡Embárcate en un viaje de aprendizaje! <a href="https://joelolawanle.com/contents">Explora más de 200 artículos escritos por expertos en desarrollo web</a>. Pégale un vistazo a <a href="https://joelolawanle.com/posts">mí blog (en inglés)</a> con contenido interesante escrito por mí.</p><p><br></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Construyendo una API REST con Node + Fastify + Sequelize + PostgreSQL ]]>
                </title>
                <description>
                    <![CDATA[ En las próximas líneas vamos a describir los pasos para realizar la implementación de una API REST que realizará las funciones de la capa de backend y será responsable de la gestión de datos de un sistema de gestiṍn de turnos o tickets.  Si deseas profundizar en cuanto a ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/construyendo-una-api-rest-con-node-fastify-sequelize-postgresql/</link>
                <guid isPermaLink="false">65590ef2bcc2a003e70e2db7</guid>
                
                    <category>
                        <![CDATA[ api rest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ fastify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ sequelize ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgresql ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Leonardo José Castillo Lacruz ]]>
                </dc:creator>
                <pubDate>Sat, 30 Dec 2023 02:29:10 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/12/btmJOTjifO9r_2560_1440.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>En las próximas líneas vamos a describir los pasos para realizar la implementación de una API REST que realizará las funciones de la capa de backend y será responsable de la gestión de datos de un sistema de gestiṍn de turnos o tickets. </p><p>Si deseas profundizar en cuanto a como funciona una API REST, sus elementos y particularidades, puedes consultar <a href="https://www.freecodecamp.org/espanol/news/consumiendo-una-api-rest-con-react-js/">este artículo de freecodecamp.org</a>, que describe de forma detallada los conceptos anteriormente mencionados.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/12/image-2.png" class="kg-image" alt="image-2" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/12/image-2.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/12/image-2.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/12/image-2.png 1024w" sizes="(min-width: 720px) 720px" width="1024" height="1024" loading="lazy"></figure><p>Cuando construimos una API REST, debemos identificar que datos para gestionar, en nuestro caso, vamos a tomar como ejemplo un sistema de gestión de tickets, que tendría un modelo de datos similar al que vemos en el siguiente diagrama:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/12/image.png" class="kg-image" alt="image" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/12/image.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2023/12/image.png 659w" width="659" height="390" loading="lazy"><figcaption>Modelo entidad-relación. Sistema de turnos/tickets</figcaption></figure><p>Tomando en cuenta lo indicado, a partir del modelo entidad-relación anterior, es importante identificar los elementos que van a actuar como componentes de nuestra API REST.</p><h2 id="elementos-componentes-de-una-api-rest">Elementos componentes de una API REST</h2><p>Vamos a identificar 3 componentes principales en la construcción de una API REST, estos son: </p><ul><li>Modelos, que serán las representación de las entidades que iremos a gestionar en la API, es la abstracción de los datos del mundo real al mundo digital.</li><li>Controladores, responsables de implementar las operaciones a realizar sobre los modelos, a veces denominada capa de lógica de negocios.</li><li>Rutas, definiciones de como nuestra API puede interactuar con el mundo exterior, es decir a través de las rutas definimos la comunicación entre la implementación que vamos a realizar con los servicios o herramientas que irán a consumir lo que realicemos.</li></ul><p>Para construir esta API vamos a usar NodeJS, que es el entorno de ejecución de javascript para backend. </p><h3 id="definiendo-a-nodejs">Definiendo a NodeJS</h3><p>Según la web oficial de <a href="https://nodejs.org/es/about" rel="noopener ugc nofollow">nodejs.org</a>, la definición de Node es:</p><blockquote><em><em>Ideado como un entorno de ejecución de JavaScript orientado a eventos asíncronos, Node.js está diseñado para crear aplicaciones network escalables.</em></em></blockquote><p>En el siguiente material tendrás algunas orientaciones básicas de como funciona y como realizar la instalación del mismo.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/BA1-NU5edwQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Introducción a Node.js: Guía para principiantes" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p> </p><h3 id="qu-es-fastify">Qué es Fastify</h3><p>Partiendo de los elementos indicados como componentes de una API, vamos a explicar que paquetes vamos a utilizar para la implementacion de cada uno de ellos. Comencemos por el responsable de las rutas o mejor en forma general, por la comunicación y transporte de datos.</p><p>Es a través de este proceso (comunicación y transporte) que nuestra API REST &nbsp;va a recibir y enviar datos a quien esté consumiendo el servicio. Esto se hace a través de rutas.</p><p>Para esta tarea tenemos varias opciones, como usar las clases nativas de NodeJS, usar el framework expressjs o &nbsp;en nuestro caso usar el framework fastify. Te preguntaras por qué Fastify?. Varias razones: simplicidad, rapidez y escabilidad del framework.</p><p>Primero vamos a crear nuestro proyecto node, con la siguiente instrucción:</p><pre><code>npm init</code></pre><p>Ahora avancemos a la instalación de fastify, esta muy simple, sólo ejecutanos el siguiente comando y con ello ya en nuestro proyecto podemos usar sus métodos y funcionalidades, pero comencemos por crear el proyecto:</p><pre><code>npm install fastify</code></pre><p>Ahora procedemos a construir el esqueleto de nuestra API.</p><h2 id="construyendo-los-elementos-de-nuestra-api-rest">Construyendo los elementos de nuestra API REST</h2><p>Empecemos por el archivo principal, el cual será: <code>index.js</code> El contenido del archivo <code>index.js</code> será:</p><pre><code>import Fastify from 'fastify';

const fastify = Fastify({
    logger: true
});

// Ruta inicial
fastify.get('/', async function handler (req, res) {
    return { hello: 'world' };
});
  
// Ejecución de la aplicación
try {
    await fastify.listen({ port: 3000 });
} catch (err) {
    fastify.log.error(err);
    process.exit(1);
}</code></pre><p>Con lo anterior, ya tenemos en pocas líneas, una API funcional, que solo tiene una ruta, pero que en esencia está completa. Ahora pasemos a la extensión de sus rutas.</p><h3 id="definiendo-las-rutas-b-sicas">Definiendo las rutas básicas</h3><p>Procedemos entonces a definir las rutas que nuestra API va a implementar, en este caso creamos un nuevo archivo llamado <code>routes.js</code>, en el cual definimos los CRUDs de cada uno de nuestros modelos, siendo que CRUD será (C-reate, R-ead, U-pdate, D-elete), en español serán las operaciones de Inserción, Lectura, Actualización y Borrado.</p><p>El archivo quedará de esta forma: </p><pre><code>const rutas = [
    {
        method: "POST",
        url: "/usuarios",
        handler: async (req, res) =&gt; {
            res.status(200).send({status: 'OK - POST'});
        }
    },
    {
        method: "GET",
        url: "/usuarios",
        handler: async (req, res) =&gt; {
            res.status(200).send({status: 'OK - GET'});
        }
    },
    {
        method: "PUT",
        url: "/usuarios/:id",
        handler: async (req, res) =&gt; {
            res.status(200).send({status: 'OK - PUT'});
        }
    },
    {
        method: "DELETE",
        url: "/usuarios/:id",
        handler: async (req, res) =&gt; {
            res.status(200).send({status: 'OK - DELETE'});
        }
    }
]

export default rutas;</code></pre><p>Observa que algunas rutas tienen <code>:/id</code>, esto lo explicaremos en detalle más adelante. </p><p>Con las rutas ya definidas, el siguiente paso será definir los modelos, notese que en el archivo anterior, dejamos la propiedad <code>handler</code> apuntando a una función básica que siempre retorna OK.</p><pre><code>handler: (req,res) =&gt; {
	res.status(200).send('OK');
}</code></pre><p>Esto significa que por ahora no tenemos ningún proceso asociado a las rutas, pero hemos dejado ya la estructura hecha. La implementación será realizada más adelante.</p><p>Incorporemos las rutas a nuestro archivo principal <code>index.js</code>, quedando este de la siguiente forma:</p><pre><code>import Fastify from 'fastify';
import rutas from './rutas.js';
import cors from '@fastify/cors';

const fastify = Fastify({logger:true});
await fastify.register(cors, {

});

//POST - Inserciones                C-REATE
//GET - Consulta                    R-EAD
//PUT, PATCH - Actualizaciones      U-PDATE
//DELETE - Borrado                  D-ELETE

fastify.get("/",async function(req, res) {
    return { hello: 'world'};
});

//Incorporación de las rutas
rutas.forEach((ruta) =&gt; {
    fastify.route(ruta);
});

try {
    fastify.listen({port:3500});
} catch(erro) {
    console.log(erro);
}
</code></pre><p>En el siguiente material podrás visualizar el paso de la construcción que hemos hecho hasta ahora.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/DuUMepfA0Z8?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="API REST con NodeJS + Fastify: Crea tu primera API RESTful desde cero" name="fitvid1"></iframe>
          </div>
        </div>
      </figure><h2 id="modelos">Modelos</h2><p>Acá vamos a definir los datos que nuestra API procesará, tomemos la primera entidad "Usuarios" y definamos su modelo, para ello nos vamos a apoyar en <code>sequelize</code>, que nos permite hacer una definición que luego se reflejará en la base de datos, esto debido a que Sequelize actua como un ORM (Object Relation Mapping).</p><h3 id="pero-qu-es-un-orm-object-relation-mapping">Pero qué es un ORM - Object Relation Mapping?</h3><p>Tomando lo que <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">https://en.wikipedia.com</a> nos indica, podemos citar lo que es un ORM:</p><blockquote>Un ORM (Object-Relational Mapping) es una técnica de programación que permite la conversión de datos entre una base de datos relacional y un lenguaje de programación orientado a objetos. En otras palabras, un ORM es una herramienta que ayuda a simplificar la traducción entre los dos paradigmas: objetos y tablas de bases de datos relacionales. Puede utilizar definiciones de clases (modelos) para crear, mantener y proporcionar acceso completo a los datos de los objetos y su persistencia en la base de datos.</blockquote><h3 id="instalando-sequelizer">Instalando Sequelizer</h3><p>Para realizar la instalación de Sequelizer, necesitamos ejecutar sólo este comnpm install sequelizerando:</p><pre><code>npm install sequelizer</code></pre><p>Ejecutando lo anterior, tenemos ya disponible el paquete en nuestro proyecto, es momento de conectar nuestra base de datos, para ello creamos un nuevo archivo llamado <code>db.js</code> y colocamos los parámetros de conexión correspondientes:</p><pre><code class="language-Javascript">/* eslint-disable require-jsdoc */
import Sequelize from 'sequelize';

/*
Clase de conexión a la base de datos
*/
class DBInstance {
	constructor() {
		const dbCfg = {
			user: '&lt;usuario_base_datos&gt;',
			host: '&lt;ip_o_dns_servidor&gt;',
			database: '&lt;nombre_base_datos&gt;',
			password: '&lt;clave_usuario_base_datos&gt;',
			port: 5432,
		};
		this.sequelize = new Sequelize(dbCfg.database, dbCfg.user, dbCfg.password, {
			host: dbCfg.host,
			dialect: 'postgres',
			logging: false,
		});
	}
}

export default new DBInstance().sequelize;
</code></pre><p>Con lo anterior, ya tenemos conexión a nuestra base de datos. Ajustamos nuestro archivo <code>index.js</code> para importar este proceso de conexión y dejarlo ejecutandose cuando sea iniciada la API. Quedando su código de esta forma:</p><pre><code>import Fastify from 'fastify';
import db from './db.js';
import rutas from './rutas.js';
import cors from '@fastify/cors';

const fastify = Fastify({logger:true});
await fastify.register(cors, {

});

//POST - Inserciones                C-REATE
//GET - Consulta                    R-EAD
//PUT, PATCH - Actualizaciones      U-PDATE
//DELETE - Borrado                  D-ELETE

// eslint-disable-next-line no-unused-vars
fastify.get('/',async function(req, res) {
	return { hello: 'world'};
});

//Incorporación de las rutas
rutas.forEach((ruta) =&gt; {
	fastify.route(ruta);
});

async function database() {
	try {
		await db.sync();
		console.log('Conectado a la base de datos');
	} catch(e) {
		console.log(e);
	}
}

try {
	fastify.listen({port:3500});
	database();
} catch(erro) {
	console.log(erro);
}</code></pre><p>Observa que hemos creado una función asincrona llamada <code>database()</code> y luego al iniciar la API, la invocamos para que se realice la conexión y sincronización del modelo.</p><p>Ahora procedemos a crear el modelo, recordando que un modelo es la representación de los datos que vamos a gestionar del mundo real en nuestra API. </p><p>Comencemos por el modelo de Usuarios:</p><pre><code>import sequelize from "sequelizer";

const User = sequelize.define("User", {
    id : {
        type: sequelize.STRING,
        allowNull: false,
        primaryKey: true,
    },
    fullname: {
        type: sequelize.STRING,
        allowNull: false,
    },
    password: {
        type: sequelize.STRING,
        allowNull: false,
    },
});

export default User;</code></pre><p>Observa que cada propiedad del objeto que define el modelo, corresponde con el nombre del campo que definimos en nuestro modelo de entidad-relación al inicio del documento, el nombre de cada propiedad representa cada campo, así que debemos tener cuidado con el nombre que le indiquemos, mi recomendación usar letras minusculas, no usar caracteres especiales.</p><p>En el caso de password, vamos usar un paquete adicional, para poder encriptar el contenido de la misma, recordando que por seguridad, los datos de claves no se deben guardar de forma plana o legible en la base de datos.</p><p>Para lograr que nuestro password quede guardado de forma segura, hacemos uso del paquete <code>bcrypt</code>, el cual nos permite codificar el valor enviado por el usuario y luego con un método propio del paquete podemos validar si clave es la guardada, de esta forma el modelo de Usuarios queda implementado con el siguiente código:</p><figure class="kg-card kg-code-card"><pre><code>import sequelize from 'sequelize';
import bcrypt from 'bcrypt';
import db from '../db.js';


const UserModel = db.define('users', {
  id: {
    type: sequelize.STRING,
    allowNull: false,
    primaryKey: true,
  },
  fullname: {
    type: sequelize.STRING,
    allowNull: false,
  },
  password: {
    type: sequelize.STRING,
    allowNull: false,
  },
}, {
  hooks: {
    beforeCreate: (user) =&gt; {
      const salt = bcrypt.genSaltSync();
      user.password = bcrypt.hashSync(user.password, salt);
    },
  },
});

UserModel.prototype.validPassword = function(password) {
  return bcrypt.compareSync(password, this.password);
};

export default UserModel;</code></pre><figcaption>Modelo de Usuarios</figcaption></figure><p>Para el caso del modelo de tiendas o comercios, siguiendo lo definido anteriormente, el modelo queda representado con el siguiente código:</p><figure class="kg-card kg-code-card"><pre><code>import sequelize from 'sequelize';
import db from '../db.js';

const StoreModel = db.define('stores', {
  id: {
    type: sequelize.INTEGER,
    autoIncrement: true,
    allowNull: false,
    primaryKey: true,
  },
  store_name: {
    type: sequelize.STRING,
    allowNull: false,
  },
  category_store: {
    type: sequelize.STRING,
    allowNull: false,
  },
});


export default StoreModel;</code></pre><figcaption>Modelo de Tiendas/Comercios</figcaption></figure><p>Algunas diferencias notorias, en el caso de id, usamos una propiedad dentro del objeto <code>id</code> que es <code>autoIncrement</code>, la cual define que el campo en la base de datos será del valor automático e incremental, de esta forma la base de datos asignará el id correspondiente. Otro punto interesante es el tipo de datos, en el caso de <code>id</code> usamos el tipo <code>INTEGER</code>, para definir que es un número entero.</p><p>Pasemos ahora al modelo de Tickets o Turnos, hacemos la implementación, recordando que este modelo se relaciona con Usuarios y Tiendas, de forma que un <em>Usuario </em>tiene N <em>Tickets </em>y una Tienda también tiene N <em>Tickets,</em> de esta forma el modelo implementado será: </p><figure class="kg-card kg-code-card"><pre><code>import sequelize from 'sequelize';
import db from '../db.js';
import UserModel from './Users.js';
import StoreModel from './Stores.js';

const TicketModel = db.define('tickets', {
  id: {
    type: sequelize.STRING,
    allowNull: false,
    primaryKey: true,
  },
  date_time: {
    type: 'TIMESTAMP',
    allowNull: false,
  },
  status: {
    // eslint-disable-next-line new-cap
    type: sequelize.ENUM(['Creado', 'Confirmado', 'Atendido', 'Cancelado',
      'En progreso']),
    allowNull: false,
  },
  observation: {
    type: sequelize.TEXT,
    allowNull: false,
  },
  end_date_time: {
    type: 'TIMESTAMP',
    allowNull: false,
  },
});

UserModel.hasMany(TicketModel, {
  foreignKey: {
    name: 'user_id',
    type: sequelize.STRING,
    allowNull: false,
  },
});

StoreModel.hasMany(TicketModel, {
  foreignKey: {
    name: 'store_id',
    type: sequelize.INTEGER,
    allowNull: false,
  },
});


export default TicketModel;
</code></pre><figcaption>Modelo de Turnos o Tickets</figcaption></figure><p>En este modelo tenemos algunas particularidades que valen la pena analizar:</p><ul><li>Tenemos nuevos tipos de datos: <code>TEXT</code>para almacenar grandes cantidad de datos (mayores a 255 caracteres), <code>ENUM</code> para definir un conjunto de valores cerrados para un campo en particular. <code>TIMESTAMP</code> para definir campos de tipo fecha/hora.</li><li>Relaciones, en este modelo le decimos a <code>sequelize</code> que queremos relacionar los modelos en este segmento de código:</li></ul><pre><code>UserModel.hasMany(TicketModel, {
  foreignKey: {
    name: 'user_id',
    type: sequelize.STRING,
    allowNull: false,
  },
});

StoreModel.hasMany(TicketModel, {
  foreignKey: {
    name: 'store_id',
    type: sequelize.INTEGER,
    allowNull: false,
  },
});</code></pre><p>Observa que se indica que el modelo Usuarios (<code>UserModel</code>) tiene muchos Tickets con la instrucción: <code>hasMany</code>, lo mismo sucede en el caso de Tiendas (<code>StoreModel</code>), le indicamos que va a tener múlples Tickets.</p><p>Con ellos hemos finalizado los modelos a implementar, ahora pasemos a la lógica de negocios.</p><h2 id="controladores">Controladores</h2><p>Estos elementos tan importantes a la hora de construir nuestra API REST, son los responsables de implementar lo que denominamos la lógica de negocios, es decir ellos reciben los datos enviados por quienes consumen el servicio o la API, los procesan, envian a la capa de datos cuando corresponde y retornan una respuesta. </p><p>De acuerdo con lo anterior, entonces en los controladores donde vamos a implementar el famoso CRUD (Create, Read, Update and Delete), el cual ya citamos anteriormente. Ahora bien, definamos la anatomía de un controlador:</p><pre><code>import Model from "../models/Model.js";

class ModeloController {
    constructor() {

    }
    
    //Creación de registros
    async create (req, res)  {
    }
    
    //Consulta de todos los registros del modelo
    async getAll(req, res) {
    }

	//Consulta de un registro en particular
    async getOne(req, res) {
    }
    
    //Actualización de un registro
    async update(req, res) {
    }
    
    
    //Borrado de un registro
    async delete(req, res) {
    }
    
 }
    </code></pre><p>Notemos que el controlador implementar como comentarmos anteriormente cada una de las operaciones del CRUD, que la API va a realizar para cada uno de los modelos construidos, de esta forma, vamos a tener que crear un controlador para usuarios, otro para tiendas y uno más para los tickets o turnos.</p><p>En este material realizamos la implementación de los modelos y parte de los controladores:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/pn7Vyj3w2wc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Creando capas de modelos y controladores en una API REST con NodeJS, Fastify, PostgreSQL y Sequelize" name="fitvid2"></iframe>
          </div>
        </div>
      </figure><p>Ahora para cada modelo que hemos definido en nuestra API, construimos sus controladores, quedando su código de esta forma:</p><ul><li>UsersController</li></ul><pre><code>/* eslint-disable require-jsdoc */
import UserModel from '../models/Users.js';

class UsersController {
  constructor() {

  }

  async create(req, res) {
    try {
      const userModel = await UserModel.create(req.body);

      if (userModel) {
        res.status(200).send({status: true, id: userModel.id});
      }
    } catch (e) {
      res.status(500).send({error: e});
    }
  }

  async getAll(req, res) {
    try {
      const where = {...req.query};
      const usuarios = await UserModel.findAll({where});
      res.status(201).send(usuarios);
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al consultar usuarios'},
      );
    }
  }

  async getOne(req, res) {
    try {
      const {id} = req.params;

      const userModel = await UserModel.findByPk(id);

      if (userModel) {
        res.status(201).send(userModel);
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al consultar el usuario'},
      );
    }
  }

  async update(req, res) {
    try {
      const {id} = req.params;

      const userModel = await UserModel.update(req.body,
          {where: {id}});

      if (typeof (userModel[0]) !== 'undefined' &amp;&amp; userModel[0] === 1) {
        res.status(201).send({
          status: true,
        });
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al actualizar el usuario'},
      );
    }
  }

  async delete(req, res) {
    try {
      const {id} = req.params;

      const userModel = await UserModel.destroy({where: {id}});

      if (userModel) {
        res.status(201).send({
          status: true,
        });
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al intentar borrar un usuario'},
      );
    }
  }
}

export default new UsersController();
</code></pre><p>Del código anterior podemos resaltar algunas caracteristicas:</p><ul><li>Todos los métodos son asincronos, es decir por ser operaciones de base de datos, estos procesos deben esperar resultados y recordamos que Javascript <em>no espera a nadie </em>por lo tanto usamos las palabras reservadas <code>async</code> e <code>await</code> para lograr ese objetivo.</li><li>Encerramos el procesamiento o la lógica de cada operación entre las palabras <code>try</code> y <code>catch</code> de forma tal que cualquier error, lo podamos capturar y retornar a quien nos consume los servicios.</li><li>En cada uno de los métodos de nuestros controladores, nos vamos a apoyar en métodos de <em>Sequelize</em>, que nos van a facilitar el acceso y la gestión de los datos a nivel de base de datos. En la creación usamos <code>create</code>, en la búsqueda usamos <code>findAll</code>, para conseguir un registro en particular usamos <code>findByPk</code>, para actualizar usamos <code>update</code> y para borrar usamos <code>destroy</code>.</li><li>En las operaciones que envuelven acceso a un registro en particular usamos del objeto <code>req</code> la propiedad <code>params</code>, es decir usamos <code>req.params</code> para obtener el id del registro. Este parámetro lo definimos en la ruta.</li><li>Cuando hacemos operaciones de envio de datos, sea en la creación o en la actualización, el cuerpo o data la recibimos en lo que se denomina el <code>body</code> de la requisición, esto se obtiene con <code>req.body</code>.</li></ul><p>Veamos como ha quedado el controlador de tiendas:</p><pre><code>import StoreModel from '../models/Stores.js';


/* eslint-disable require-jsdoc */
class StoreController {
  constructor() {

  }

  async create(req, res) {
    try {
      const storeModel = await StoreModel.create(req.body);

      if (storeModel) {
        res.status(201).send({status: true, id: storeModel.id});
      }
    } catch (e) {
      res.status(500).send(e);
    }
  }

  async getAll(req, res) {
    try {
      const where = req.query;

      const tiendas = await StoreModel.findAll({where});
      res.status(201).send(tiendas);
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al consultar tiendas'},
      );
    }
  }

  async getOne(req, res) {
    try {
      const {id} = req.params;

      const storeModel = await StoreModel.findByPk(id);
      if (storeModel) {
        res.status(201).send(storeModel);
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al consultar la tienda'},
      );
    }
  }

  async update(req, res) {
    try {
      const {id} = req.params;
      const data = {...req.body};

      delete data.id;

      const storeModel = await StoreModel.update(data,
          {where: {id}});

      if (typeof (storeModel[0]) !== 'undefined' &amp;&amp; storeModel[0] === 1) {
        res.status(201).send({
          status: true,
        });
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al actualizar la tienda'},
      );
    }
  }

  async delete(req, res) {
    try {
      const {id} = req.params;

      const storeModel = await StoreModel.destroy({where: {id}});

      if (storeModel) {
        res.status(201).send({
          status: true,
        });
      } else {
        res.status(404).send(
            {message: 'Registro no encontrado'},
        );
      }
    } catch (err) {
      res.status(500).send(
          {message: err.message || 'Error al intentar borrar una tienda'},
      );
    }
  }
}

export default new StoreController();</code></pre><p>El controlador es bien similar al de usuarios, implementado en la clase <code>UserController</code>, solo en el método de actualización (<code>update</code>), agregamos está linea: <code>delete data.id;</code> para evitar que sea modificar el id interno del registro.</p><p>El controlador de Turnos, sigue a continuación, este controlador también tiene la protección para evitar que el campo autonumérico sea modificado en el método de actualización (<code>update</code>). </p><pre><code>import TicketModel from '../models/Tickets.js';

/* eslint-disable require-jsdoc */
class TicketController {
	constructor() {

	}

	async create(req, res) {
		try {
			const ticketModel = await TicketModel.create(req.body);

			if (ticketModel) {
				res.status(201).send({status: true, id: ticketModel.id});
			}
		} catch (e) {
			res.status(500).send(e);
		}
	}

	async getAll(req, res) {
		try {
			const where = req.query;

			const tickets = await TicketModel.findAll({where});
			res.status(201).send(tickets);
		} catch (err) {
			res.status(500).send(
				{message: err.message || 'Error al consultar tickets'},
			);
		}
	}

	async getOne(req, res) {
		try {
			const {id} = req.params;

			const ticketModel = await TicketModel.findByPk(id);
			if (ticketModel) {
				res.status(201).send(ticketModel);
			} else {
				res.status(404).send(
					{message: 'Registro no encontrado'},
				);
			}
		} catch (err) {
			res.status(500).send(
				{message: err.message || 'Error al consultar el ticket'},
			);
		}
	}

	async update(req, res) {
		try {
			const {id} = req.params;
			const data = {...req.body};
			delete data.id;

			const ticketModel = await TicketModel.update(data,
				{where: {id}});

			if (typeof (ticketModel[0]) !== 'undefined' &amp;&amp; ticketModel[0] === 1) {
				res.status(201).send({
					status: true,
				});
			} else {
				res.status(404).send(
					{message: 'Registro no encontrado'},
				);
			}
		} catch (err) {
			res.status(500).send(
				{message: err.message || 'Error al actualizar el ticket'},
			);
		}
	}

	async delete(req, res) {
		try {
			const {id} = req.params;

			const ticketModel = await TicketModel.destroy({where: {id}});

			if (ticketModel) {
				res.status(201).send({
					status: true,
				});
			} else {
				res.status(404).send(
					{message: 'Registro no encontrado'},
				);
			}
		} catch (err) {
			res.status(500).send(
				{message: err.message || 'Error al intentar borrar un ticket'},
			);
		}
	}
}

export default new TicketController();
</code></pre><p>Con esto hemos finalizado los controladores.</p><h2 id="rutas-actualizadas">Rutas actualizadas</h2><p>Ahora es momento de revisar como llamamos todo lo implementado en nuestras rutas, recordando que al inicio generamos las rutas para el módelo de usuarios, pero llamando a métodos genéricos en lugar de nuestros controladores, con ellos implementados, podemos ajustar el código, el cual queda de la siguiente forma:</p><pre><code>import UsersController from './controllers/Users.js';
import StoreController from './controllers/Stores.js';
import TicketController from './controllers/Tickets.js';

const rutas = [
	{
		method: 'POST',
		url: '/usuarios',
		handler: UsersController.create,
	},
	{
		method: 'GET',
		url: '/usuarios',
		handler: UsersController.getAll,
	},
	{
		method: 'GET',
		url: '/usuarios/:id',
		handler: UsersController.getOne,
	},
	{
		method: 'PUT',
		url: '/usuarios/:id',
		handler: UsersController.update,
	},
	{
		method: 'DELETE',
		url: '/usuarios/:id',
		handler: UsersController.delete,
	},

	/* Rutas de tiendas */
	{
		method: 'POST',
		url: '/tiendas',
		handler: StoreController.create,
	},
	{
		method: 'GET',
		url: '/tiendas',
		handler: StoreController.getAll,
	},
	{
		method: 'GET',
		url: '/tiendas/:id',
		handler: StoreController.getOne,
	},
	{
		method: 'PUT',
		url: '/tiendas/:id',
		handler: StoreController.update,
	},
	{
		method: 'DELETE',
		url: '/tiendas/:id',
		handler: StoreController.delete,
	},

	/* Rutas de turnos */
	{
		method: 'POST',
		url: '/turnos',
		handler: TicketController.create,
	},
	{
		method: 'GET',
		url: '/turnos',
		handler: TicketController.getAll,
	},
	{
		method: 'GET',
		url: '/turnos/:id',
		handler: TicketController.getOne,
	},
	{
		method: 'PUT',
		url: '/turnos/:id',
		handler: TicketController.update,
	},
	{
		method: 'DELETE',
		url: '/turnos/:id',
		handler: TicketController.delete,
	},
];

export default rutas;</code></pre><p>Interesante que nuestro archivo raiz <code>index.js</code> no sufre ninguna alteración, esto debido al grado de encapsulamiento y desacoplamiento que hemos implementado.</p><p>Con esto ya tenemos una API Rest funcional, implementada con NodeJS, Fastify, Sequelize y PostgreSQL.</p><p>Puedes verificar la implementación de los controladores y de todos sus métodos en este material:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/vvlWMU7mbiA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Construyendo una API RESTful con Node, Fastify, Sequelize y Postgres: Parte 3 - Finalizando el CRUD" name="fitvid3"></iframe>
          </div>
        </div>
      </figure> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
