diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..b6ae71f --- /dev/null +++ b/404.html @@ -0,0 +1,824 @@ + + + +
+ + + + + + + + + + + + + + + + + + +En el desarrollo de aplicaciones modernas, la capacidad de interactuar eficientemente con servicios externos a través de APIs es fundamental. Esta sección está dedicada a explorar cómo podemos integrar nuestra aplicación Next.js con diferentes servicios API, enfocándonos principalmente en la comunicación con APIs REST.
+La comunicación entre el frontend de una aplicación y el backend se realiza a menudo a través de APIs REST, utilizando el protocolo HTTP. Este método de integración permite a las aplicaciones web interactuar con bases de datos y servidores sin necesidad de recargar la página, ofreciendo una experiencia de usuario fluida y dinámica. En esta sección, exploraremos los tipos de peticiones HTTP más comunes en APIs REST y cómo se utilizan para diferentes operaciones CRUD (Crear, Leer, Actualizar, Eliminar).
+GET: Se utiliza para solicitar datos de un recurso específico. Las peticiones GET deben ser solo de lectura y no modificar los datos del servidor Una característica importante de GET es que los parámetros de la solicitud se envían en la URL. Los navegadores tienden a cachear las respuestas de las peticiones GET, lo que puede ser útil para mejorar la eficiencia y velocidad de carga de las aplicaciones web.
+POST: Se usa para enviar datos a un servidor para crear o actualizar un recurso. Los datos se envían en el cuerpo de la solicitud, no en la URL, lo que permite enviar información más compleja y segura. A diferencia de GET, POST no es cacheado por los navegadores, lo que lo hace más seguro para operaciones que implican cambios o la transferencia de información sensible.
+PUT: Similar a POST, pero se utiliza principalmente para actualizar recursos existentes. Si el recurso no existe, PUT puede crear uno nuevo.
+DELETE: Como su nombre indica, se utiliza para eliminar recursos especificados.
+PATCH: Se usa para aplicar actualizaciones parciales a un recurso. A diferencia de PUT, que reemplaza completamente el recurso, PATCH modifica solo los campos especificados.
+Como este tutorial trata sobre frontend, no vamos a desarrollar un back. Usaremos un servidor de pruebas que +permite enviar y guardar datos desde un fichero de texto.
+Para ello vamos a ejecutar lo siguiente:
+npm add --save-dev json-server
+npx npm-add-script -f -k db:start -v "mkdir -p node_modules/.cache && echo '{\"counters\":[{\"id\": 1, \"value\": 0}]}' > node_modules/.cache/db.json && json-server --port 4000 --watch node_modules/.cache/db.json"
+
Y ya podemos ejecutarlo en un terminal aparte:
+ +Podemos acceder desde el navegador, que por defecto hace peticiones GET, y visualizar los datos que contiene:
+Para crear datos, necesitamos usar POST. No podemos usar el navegador, pero podemos usar un cliente como curl
:
Example
+Crear un nuevo contador
+ +Para actualizar datos, tendremos que usar la url del contador. Dependiendo del servidor, deberemos usar POST, PUT o PATCH.
+Example
+Si el ejemplo anterior nos devolvió un contador con el id 2
, podemos actualizarlo así:
O podemos usar PUT:
+ +Para manejar las solicitudes HTTP de manera efectiva y eficiente en React, podemos utilizar la combinación de Axios para realizar las peticiones y la librería SWR para el fetching y caching de datos. Esto nos permite crear aplicaciones más rápidas y con mejor respuesta al usuario.
+Primero, necesitas instalar axios
para manejar las peticiones HTTP y swr
para el manejo de datos. Ejecuta el siguiente comando en tu terminal para instalar ambas librerías:
Para simplificar las peticiones HTTP y establecer una URL base para todas las llamadas, configura un cliente Axios. Crea un archivo en src/utils/fetcher.ts y define tu cliente Axios y una función fetcher que utilizará SWR para hacer las peticiones.
+import axios from 'axios'
+
+export const client = axios.create({
+ baseURL: 'http://localhost:4000',
+})
+
+export async function fetcher(url: string) {
+ return client.get(url).then((response) => response.data)
+}
+
Una vez que tienes tu función fetcher definida, puedes usarla con SWR en tus componentes React para acceder a los datos del servidor. SWR manejará automáticamente el caching, la revalidación, y otras optimizaciones.
+'use client'
+
+import useSWR from 'swr'
+
+import { client, fetcher } from '@/utils/fetcher'
+
+import { CounterProperties } from './types'
+
+async function updateCounter(id: number, value: number) {
+ return await client.patch(`/counters/${id}`, { value })
+}
+
+function useCounter(id: number) {
+ const { data, isLoading, mutate } = useSWR(`/counters/${id}`, fetcher)
+
+ const counter: number = data?.value ?? 0
+
+ const onIncrement = async (value: number) => {
+ const {
+ data: { value: updatedValue },
+ } = await updateCounter(id, counter + value)
+ mutate({ ...data, value: updatedValue }, false)
+ }
+
+ const onDecrement = async (value: number) => {
+ const {
+ data: { value: updatedValue },
+ } = await updateCounter(id, counter - value)
+ mutate({ ...data, value: updatedValue }, false)
+ }
+
+ const onReset = async () => {
+ const {
+ data: { value: updatedValue },
+ } = await updateCounter(id, 0)
+ mutate({ ...data, value: updatedValue }, false)
+ }
+
+ return { counter, isLoading, onDecrement, onIncrement, onReset }
+}
+
+export function Counter({ id, step }: CounterProperties) {
+ const { counter, isLoading, onDecrement, onIncrement, onReset } =
+ useCounter(id)
+
+ if (isLoading) {
+ return (
+ <Card className="w-[240px] h-[132px]">
+ <Skeleton>
+ <div className="h-24 rounded-lg bg-default-300"></div>
+ </Skeleton>
+ </Card>
+ )
+ }
+
+ return (
+ <Card className="w-[240px] bg-gradient-to-br from-violet-500 to-fuchsia-500">
+ <CardHeader className="flex-col items-start">
+ <div className="flex flex-col">
+ <p className="text-tiny text-white/60 uppercase font-bold">
+ Contador #{id}
+ </p>
+ <p className="text-white font-medium text-large">
+ El contador vale {counter}.
+ </p>
+ </div>
+ </CardHeader>
+ <CardFooter className="justify-center">
+ <ButtonGroup>
+ <Button isIconOnly size="md" aria-label="Decrement counter by step">
+ <ChevronDoubleLeftIcon
+ className="text-gray-600 dark:text-gray-400"
+ height="1.3rem"
+ />
+ <div className="absolute right-1 bottom-0 font-bold text-[10px]">
+ -{step * 10}
+ </div>
+ </Button>
+ <Button
+ isIconOnly
+ size="md"
+ aria-label="Decrement counter"
+ onClick={() => onDecrement(1)}
+ >
+ <ChevronLeftIcon
+ className="text-gray-600 dark:text-gray-400"
+ height="1.3rem"
+ />
+ <div className="absolute right-1 bottom-0 font-bold text-[10px]">
+ -{step}
+ </div>
+ </Button>
+ <Button
+ isIconOnly
+ size="md"
+ aria-label="Reset counter"
+ onClick={() => onReset()}
+ >
+ <ArrowPathIcon
+ className="text-gray-600 dark:text-gray-400"
+ height="1.3rem"
+ />
+ </Button>
+ <Button
+ isIconOnly
+ size="md"
+ aria-label="Increment counter"
+ onClick={() => onIncrement(1)}
+ >
+ <ChevronRightIcon
+ className="text-gray-600 dark:text-gray-400"
+ height="1.3rem"
+ />
+ <div className="absolute right-1 bottom-0 font-bold text-[10px]">
+ +{step}
+ </div>
+ </Button>
+ <Button isIconOnly size="md" aria-label="Increment counter by step">
+ <ChevronDoubleRightIcon
+ className="text-gray-600 dark:text-gray-400"
+ height="1.3rem"
+ />
+ <div className="absolute right-1 bottom-0 font-bold text-[10px]">
+ +{step * 10}
+ </div>
+ </Button>
+ </ButtonGroup>
+ </CardFooter>
+ </Card>
+ )
+}
+
{"use strict";/*!
+ * escape-html
+ * Copyright(c) 2012-2013 TJ Holowaychuk
+ * Copyright(c) 2015 Andreas Lubbe
+ * Copyright(c) 2015 Tiancheng "Timothy" Gu
+ * MIT Licensed
+ */var Va=/["'&<>]/;qn.exports=za;function za(e){var t=""+e,r=Va.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i