Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
November 4, 2022 02:00 pm GMT

Como hacer peticiones a la API con Axios y React JS.

En esta ocasin aprenders a como realizar peticiones HTTP bsicas (GET, POST, PUT, DELETE) con ayuda de axios y usando React JS.

Cualquier tipo de Feedback es bienvenido, gracias y espero disfrutes el articulo.

Tabla de contenido.

Tecnologas a utilizar.

Creando el proyecto.

Primeros pasos.

Qu es axios?

Creando una nueva instancia de axios.

Creando la peticin GET.

Creando la peticin POST.

Creando la peticin PUT.

Creando la peticin DELETE.

Manejando errores.

Conclusin.

Demostracin.

Cdigo fuente.

Tecnologas a utilizar.

  • React JS (version 18)
  • Vite JS
  • TypeScript
  • Axios
  • CSS vanilla (Los estilos los encuentras en el repositorio al final de este post)

Creando el proyecto.

Al proyecto le colocaremos el nombre de: axios-react (opcional, tu le puedes poner el nombre que gustes).

npm init vite@latest

Creamos el proyecto con Vite JS y seleccionamos React con TypeScript.

Luego ejecutamos el siguiente comando para navegar al directorio que se acaba de crear.

cd axios-react

Luego instalamos las dependencias.

npm install

Despus abrimos el proyecto en un editor de cdigo (en mi caso VS code).

code .

Primeros pasos.

Dentro del archivo src/App.tsx borramos todo y creamos un componente que muestre un hola mundo

const App = () => {    return (        <div>Hello world</div>    )}export default App

La idea es crear cuatro diferentes componentes, y cada componente har una tipo de peticin (GET, POST, PUT, DELETE).
De antemano te menciono que habr cdigo repetido. Si tu deseas puedes refactorizar, pero yo no lo hare porque mi propsito es ensearte a usar axios!

Creamos la carpeta src/components y dentro creamos 4 archivos:

  • CreatePost.tsx
  • GetPost.tsx
  • UpdatePost.tsx
  • DeletePost.tsx

Nota: Cada vez que creamos una nueva carpeta, tambin crearemos un archivo index.ts para agrupar y exportar todas las funciones y componentes de otros archivos que estn dentro de la misma carpeta, y que dichas funciones puedan ser importadas a traves de una sola referencia a esto se le conoce como archivo barril.

Qu es axios?.

Axios es una librera cliente HTTP basada en promesas que se puede usar tanto en Node JS como en el navegador; por lo que podremos configurar y realizar solicitudes a un servidor y recibiremos respuestas fciles de procesar.
Nos ayuda en el envi de peticiones asncronas HTTP, asi ayudndonos a realizar las operaciones CRUD.
Ademas es una buena alternativa al Fetch API por defecto de los navegadores.

Creando una nueva instancia de axios.

Primero instalamos axios:

npm install axios

Vamos a crear la carpeta src/api y creamos el archivo client.ts
Dentro del archivo, vamos a importar axios y vamos a crear una nueva instancia de axios (la mayora de las veces siempre vas a querer hacer esto).

Esto nos ayuda a tener una configuracin centralizada en un lugar y personalizada, ya que la mayora de los casos no queremos andar colocando la misma configuracin cada vez que hagamos una peticin.

La propiedad create de axios recibe un objeto de configuracin, donde en este caso de pasamos la propiedad baseURL, que es la url base a la que haremos las peticiones

Tambin le pueden establecer los headers, el timeout (numero que indica el tiempo en milisegundos para que la peticin sea abortada), y otras propiedades, pero solo con el base URL nos basta para este ejemplo.

Vamos a usar la API de JSONPlaceholder para hacer las peticiones.

Y de una vez definimos, aqu mismo, la interfaz de la respuesta que nos va a dar la API.

import axios from 'axios';export const client = axios.create({    baseURL: "https://jsonplaceholder.typicode.com/posts"})export interface ResponseAPI {    userId: number;    id: number;    title: string;    body: string;}

Creando la peticin GET.

Primero vamos a src/App.tsx y vamos a importar todos los componentes que creamos con anterioridad.
Vamos a colocar primero el GetPost y luego lo comentaremos para poner el siguiente y asi sucesivamente.

import { CreatePost, DeletePost, GetPost, UpdatePost } from "./components"const App = () => {  return (    <div>      <GetPost />    </div>  )}export default App

Ahora dentro de src/components en el archivo GetPost.tsx, vamos a crear un componente que va a mostrar unas tarjetas que provienen de la API.

  • Primero tenemos un estado que almacena los post que sera un arreglo.
  • Despus, tenemos el JSX que solo mostramos unos textos y recorremos la variable de estado posts y renderizamos la informacin que nos debera dar la API.
import { useState } from 'react';import { ResponseAPI } from '../api';export const GetPost = () => {    const [posts, setPosts] = useState<ResponseAPI[]>([])    return (        <>            <h1>Get Post </h1><br />            <h2>posts list</h2>            <div className='grid'>                {                    posts.map(post => (                        <div key={post.id}>                            <p>Title: <span>{post.title}</span></p>                            <p>Body: <span>{post.body}</span></p>                            <p>User: <span>{post.userId}</span></p>                        </div>                    ))                }            </div>        </>    )}

Luego, vamos a crear una nueva carpeta src/utils donde crearemos varios archivos, el primero es getData.ts

Para usar axios es muy sencillo, solamente importamos la instancia que creamos.

Primero creamos una funcin, que sera asncrona y retornara una promesa que resuelve un arreglo de ResponseAPI.

export const getPosts = async (): Promise<ResponseAPI[]> => {}

Ahora vamos a usar la instancia de axios, dicha instancia usamos el mtodo get que nos proporciona la instancia.

import { client, ResponseAPI } from "../api"export const getPosts = async (): Promise<ResponseAPI[]> => {    await client.get('')}

Nota que ejecutamos la funcin get y dentro colocamos unas comillas vacas, por que?

Bueno esto es necesario para hacerle saber a la instancia que no queremos agregar mas parmetros a nuestra URL base.

Porque por el momento tenemos la URL asi: "https://jsonplaceholder.typicode.com/posts", por lo que agreguemos dentro del mtodo get (o cualquier otro mtodo) se concatenara a la esta URL.

Por eso solo colocamos comillas simples y vacas haciendo referencia a que no queremos concatenar nada.

Pero si queremos concatenar algo como por ejemplo el limite de resultados de la API lo colocaremos de la siguiente manera:

import { client, ResponseAPI } from "../api"export const getPosts = async (): Promise<ResponseAPI[]> => {    await client.get('?_limit=6')}

Ahora, esta promesa nos devuelve un objeto que contiene varias propiedades como la configuracin, los headers, el estado de la peticin, entre otros pero el que nos interesa es la propiedad data. La propiedad data es lo que vamos a retornar, porque es ahi donde vendr la respuesta de la API.

Nota que tambin esta tipado el mtodo get con ResponseAPI[], por si las dudas, y aunque no loe pongas el tipo y retornes la data, funcionara porque la propiedad data por defecto es de tipo any.

import { client, ResponseAPI } from "../api"export const getPosts = async (): Promise<ResponseAPI[]> => {    const { data } = await client.get<ResponseAPI[]>('?_limit=6')    return data}

Asi de fcil es hacer una peticin GET.

Ahora devuelta a src/components/GetPost.tsx

Implementamos un efecto para hacer la llamada a la API (en esta ocasin la haremos asi, aunque lo recomendable es usar una librera para manejar el cache de las peticiones como React Query)

Dentro del efecto ejecutamos la funcin getPosts y resolvemos la promesa para despus establecer la data que nos regresa dicha promesa.

import { useState, useEffect } from 'react';import { ResponseAPI } from '../api';import { getPosts } from '../utils';export const GetPost = () => {    const [posts, setPosts] = useState<ResponseAPI[]>([])    useEffect(() => {        // You can implement a <Loading/>        //  start loading        getPosts().then(data => setPosts(data))        //  finish loading    }, [])    return (        <>            <h1>Get Post </h1><br />            <h2>posts list</h2>            <div className='grid'>                {                    posts.map(post => (                        <div key={post.id}>                            <p>Title: <span>{post.title}</span></p>                            <p>Body: <span>{post.body}</span></p>                            <p>User: <span>{post.userId}</span></p>                        </div>                    ))                }            </div>        </>    )}

Y asi lucira la data de la API ya renderizada
first

Creando la peticin POST.

Ahora vamos al archivo src/components/CreatePost.tsx y creamos un nuevo componente similar al anterior.

Este componente renderiza la misma lista de post y los almacena en un estado tambin.

Nota que la key, al momento de recorrer el estado de posts, es post.userId porque este es el nico valor que es diferente cuando creamos un nuevo post.

Tambin nota que se agrego un botn, para crear post, lo haremos sin un formulario, pero lo mejor seria recibir los valores por un formularios.

Este botn, en su evento onClick ejecuta la funcin handleClick, que por el momento no hace nada, pero ahi es donde tenemos que ejecutar le mtodo para crear un nuevo post.

import { useState } from 'react';import { ResponseAPI } from '../api';export const CreatePost = () => {    const [posts, setPosts] = useState<ResponseAPI[]>([])    const handleClick = async () => {}    return (        <div>            <h1>Create Post </h1>            <button onClick={handleClick}>Add Post</button>            <div className='grid'>                {                    posts.map(post => (                        <div key={post.userId}>                            <p>Title: <span>{post.title}</span></p>                            <p>Body: <span>{post.body}</span></p>                            <p>User: <span>{post.userId}</span></p>                        </div>                    ))                }            </div>        </div>    )}

Despus, vamos a crear un nuevo archivo en src/utils nombrado createPost.ts

Dentro del archivo creamos una nueva funcin que nos retorne una promesa resolviendo un solo ResponseAPI. Y tambin, esta funcin recibe algunos parmetros que son los necesarios para crear un nuevo post.

import { client, ResponseAPI } from '../api';export const createPost = async (title: string, body: string, userId: number): Promise<ResponseAPI> => {}

Dentro de la funcin llamamos a la instancia y ejecutamos su mtodo post, el cual tambin nos da acceso, una vez resuelta la promesa, a el objeto data.

Nota que tambin debemos indicarle, si se necesita concatenar a la URL base o no, en este caso no, por eso solo colocamos comillas vacas

import { client, ResponseAPI } from '../api';export const createPost = async (title: string, body: string, userId: number): Promise<ResponseAPI> => {    const { data } = await client.post('')    return data}

Pero el mtodo post no solo recibe la URL, sino que tambin necesita el body o sea la data a enviar para crear nueva informacin.
Asi que ese body, se lo pasamos como segundo parmetro, en un objeto.

import { client, ResponseAPI } from '../api';export const createPost = async (title: string, body: string, userId: number): Promise<ResponseAPI> => {    const { data } = await client.post('', { title, body, userId })    return data}

Listo, ya tenemos nuestra funcin para crear un nuevo post, ahora vamos a usarla en src/components/CreatePost.tsx

En la funcin handleClick llamamos a la funcin createPost y le pasamos los parmetros necesarios. Usamos async/await para resolver la promesa que nos retorna la funcin createPost, que si todo sale correcto, nos debe retornar un nuevo post.

Este nuevo post, lo vamos agregar al estado, manteniendo los posts anteriores.

import { useState } from 'react';import { ResponseAPI } from '../api';import { createPost } from '../utils';export const CreatePost = () => {    const [posts, setPosts] = useState<ResponseAPI[]>([])    const handleClick = async () => {        const newPost = await createPost("new title", "something", Date.now())        setPosts(prev => ([newPost, ...prev]))    }    return (        <div>            <h1>Create Post </h1>            <button onClick={handleClick}>Add Post</button>            <div className='grid'>                {                    posts.map(post => (                        <div key={post.userId}>                            <p>Title: <span>{post.title}</span></p>                            <p>Body: <span>{post.body}</span></p>                            <p>User: <span>{post.userId}</span></p>                        </div>                    ))                }            </div>        </div>    )}

Probablemente no veamos nada, pero recuerden comentar el anterior componente y colocar el nuevo, en src/App.tsx

import { CreatePost, DeletePost, GetPost, UpdatePost } from "./components"const App = () => {  return (    <div>        {/* <GetPost /> */}        <CreatePost/>    </div>  )}export default App

create post

Creando la peticin PUT.

Primero vamos a cambiar el componente en src/App.tsx

import { CreatePost, DeletePost, GetPost, UpdatePost } from "./components"const App = () => {  return (    <div>        {/* <GetPost /> */}        {/* <CreatePost /> */}        <UpdatePost/>    </div>  )}export default App

Luego vamos a src/components/UpdatePost.tsx para crear un nuevo componente funcional que es igual al de GetPost.tsx. ya que necesitamos una lista de posts existentes para poder actualizar alguno.

Nota que el div que se renderiza al momento de recorrer los post:

  • Tiene un className='card'
  • Tiene un evento onClick que ejecuta la funcin handleUpdate y le mandamos el id del post como parmetro.

La funcin handleUpdate es asncrona y recibe el id del post que es de tipo numero, y por el momento no ejecuta nada.

import { useState, useEffect } from 'react';import { ResponseAPI } from '../api';import { getPosts } from '../utils';export const UpdatePost = () => {    const [posts, setPosts] = useState<ResponseAPI[]>([])    useEffect(() => {        getPosts().then(data => setPosts(data))    }, [])    const handleUpdate = async (id: number) => {}    return (        <div>            <h1>Update Post </h1><br />            <h2>Click a card</h2>            <div className='grid'>                {                    posts.map(post => (                        <div className='card' key={post.id} onClick={() => handleUpdate(post.id)}>                            <p>Title: <span>{post.title}</span></p>                            <p>Body: <span>{post.body}</span></p>                            <p>User: <span>{post.userId}</span></p>                        </div>                    ))                }            </div>        </div>    )}

Despus, vamos a src/utils creamos un nuevo archivo updatePost.ts

Donde bsicamente es casi igual que el mtodo post.

Nota que ahora los parmetros de la funcin estn definidas en una interfaz.

La nica diferencia entre el post y el put es que en la URL si tenemos que colocar un nuevo parmetro que es el id del post que queremos modificar.

import { client, ResponseAPI } from '../api/client';interface Props {    id: number,    userId: number,    body: string,    title: string}export const updatePost = async ({ id, body, title, userId }: Props): Promise<ResponseAPI> => {    const { data } = await client.put(`${id}`, { body, title, userId })    return data}

Ahora vamos a usar nuestra funcin, en src/components/UpdatePost.tsx

El la funcin handleUpdate llamamos a la funcin updatePost y le pasamos los parmetros necesarios, nuevamente usamos async/await para resolver la promesa y obtener el post actualizado.

Finalmente establecemos un nuevo estado, colocando el post actualizado.

import { useState, useEffect } from 'react';import { ResponseAPI } from '../api';import { getPosts, updatePost } from '../utils';export const UpdatePost = () => {    const [posts, setPosts] = useState<ResponseAPI[]>([])    useEffect(() => {        getPosts().then(data => setPosts(data))    }, [])    const handleUpdate = async (id: number) => {        const body = `Body updated`        const title = `Title updated`        const userId = Date.now()        const postUpdated = await updatePost({ id, body, title, userId })        setPosts(prev => ([            postUpdated,            ...prev.filter(post => post.id !== id),        ]))    }    return (        <div>            <h1>Update Post </h1><br />            <h2>Click a card</h2>            <div className='grid'>                {                    posts.map(post => (                        <div className='card' key={post.id} onClick={() => handleUpdate(post.id)}>                            <p>Title: <span>{post.title}</span></p>                            <p>Body: <span>{post.body}</span></p>                            <p>User: <span>{post.userId}</span></p>                        </div>                    ))                }            </div>        </div>    )}

update post

Creando la peticin DELETE.

Primero vamos a cambiar el componente en src/App.tsx

import { CreatePost, DeletePost, GetPost, UpdatePost } from "./components"const App = () => {  return (    <div>        {/* <GetPost /> */}        {/* <CreatePost /> */}        {/* <UpdatePost /> */}        <DeletePost/>    </div>  )}export default App

Luego vamos a src/components/DeletePost.tsx para crear un nuevo componente funcional que es igual al de UpdatePost.tsx. ya que necesitamos una lista de posts existentes para poder eliminar alguno.

Y ahora tenemos la funcin handleDelete que recibe un id y por el momento no hace nada.

Nota que ahora el evento onClick en cada post, ejecuta una funcin llamada handleDelete y se le pasa el id del post

import { getPosts } from "../utils"import { useEffect, useState } from 'react';import { ResponseAPI } from "../api";export const DeletePost = () => {    const [posts, setPosts] = useState<ResponseAPI[]>([])    useEffect(() => {        getPosts().then(data => setPosts(data))    }, [])    const handleDelete = async (id: number) => {    }    return (        <>            <h1>Delete Post </h1> <br />            <h2>Click a card</h2>            <div className="grid">                {                    posts.map(post => (                        <div className="card" key={post.id} onClick={() => handleDelete(post.id)}>                            <p>ID: <span>{post.id}</span></p>                            <p>Title: <span>{post.title}</span></p>                            <p>Body: <span>{post.body}</span></p>                        </div>                    ))                }            </div>        </>    )}

Entonces necesitamos crear un nuevo archivo src/utils nombrado deletePost.ts que adentro tendr una funcin asncrona que solo retornara una promesa resolviendo un valor booleano para indicar si la eliminacin del post se hizo correctamente.

Solamente llamamos al mtodo delete de nuestra instancia y agregamos el ID del post que vamos a eliminar.

En ese caso disponemos de las mismas propiedades que cuando ejecutamos un get, post o put. Pero la data nos nos sirve porque llegara un objeto vaci, en este caso evaluaremos el cdigo de estado de la peticin, si es un estado 200 significa que todo salio bien entonces retornara un true.

import { client } from '../api';export const deletePost = async (id: number): Promise<Boolean> => {    const { status } = await client.delete(`${id}`);    return status === 200}

Ahora vamos a usar esta funcin en src/components/DeletePost.tsx

Dentro de la funcin handleDelete ejecutamos la funcin deletePost mandando el ID del post que queremos eliminar, y mediante async/await resolvemos la promesa para obtener el valor booleano y en base a ese valor, actualizar el estado.

import { deletePost, getPosts } from "../utils"import { useEffect, useState } from 'react';import { ResponseAPI } from "../api";export const DeletePost = () => {    const [posts, setPosts] = useState<ResponseAPI[]>([])    useEffect(() => {        getPosts().then(data => setPosts(data))    }, [])    const handleDelete = async (id: number) => {        const isSuccess = await deletePost(id)        if (isSuccess) setPosts(prev => prev.filter(post => post.id !== id))    }    return (        <>            <h1>Delete Post </h1> <br />            <h2>Click a card</h2>            <div className="grid">                {                    posts.map(post => (                        <div className="card" key={post.id} onClick={() => handleDelete(post.id)}>                            <p>ID: <span>{post.id}</span></p>                            <p>Title: <span>{post.title}</span></p>                            <p>Body: <span>{post.body}</span></p>                        </div>                    ))                }            </div>        </>    )}

delete post

Manejando errores.

Manejar los errores con axios, solamente basta con ir a nuestras funciones helper (src/utils/) y usar un try/catch ya que hemos estado usando async/await.

Dentro del try colocamos todo el cdigo que queremos ejecutar.

Dentro del catch, vamos a recibir el error si es que algo sale mal, por ejemplo: error en la solicitud, error en el servidor, entro otros.
Este error que recibimos por parmetro, lo podemos castear a un tipo que no ofrece axios que es AxiosError y asi tener el autocompletado.

Este error tiene varias propiedades, pero la mas comn es el mensaje de error y el nombre del error.

Finalmente nota que en el catch retornamos un arreglo vaci, esto es para cumplir con el contrato de la funcin ya que debemos devolver una promesa tipo ResponseAPI[]

import { AxiosError } from "axios"import { client, ResponseAPI } from "../api"export const getPosts = async (): Promise<ResponseAPI[]> => {    try {        const { data } = await client.get('?_limit=6')        return data    } catch (error) {        const err = error as AxiosError        console.log(err.message)        console.log(err.name)        return []    }}

Conclusin.

Sin duda axios es una librera muy potente, aunque no te estoy diciendo que sea de uso obligatorios, es una librera muy util que te servir en algn proyecto.

Espero que te haya gustado esta publicacin y que tambin espero haberte ayudado a entender como realizar peticiones bsicas HTTP con esta librera, una alternativa a Fetch API.

Si conoces alguna otra forma distinta o mejor de realizar esta aplicacin con gusto puedes comentarla.

Te invito a que revises mi portafolio en caso de que ests interesado en contactarme para algn proyecto! Franklin Martinez Lucas

No olvides seguirme tambin en twitter: @Frankomtz361

Demostracin simple.

Hice unos cambios en el App.tsx para que no tengas que ir al cdigo y comentar el componente y probar cada tipo de peticin

https://axios-reactjs-app.netlify.app/

demo

Cdigo fuente.

El cdigo de App.tsx esta un poco diferente, pero el resto sigue igual.

GitHub logo Franklin361 / axios-react

Learn how to use axios with react

How to make API requests with Axios and React JS.

This time, we are going to make API requests using axios and react js!

demo

Features

  1. get posts.
  2. create posts.
  3. update posts by id
  4. delete post by id.
  5. handling errors.

Technologies

  • React JS (v 18)
  • Vite JS
  • TypeScript
  • Axios
  • CSS vanilla

Installation

  1. Clone the repository (you need to have Git installed).
    git clone https://github.com/Franklin361/axios-react
  1. Install dependencies of the project.
    npm install
  1. Run the project.
    npm run dev

Article links

Here's the link to the tutorial in case you'd like to take a look at it! eyes


Original Link: https://dev.to/franklin030601/como-hacer-peticiones-a-la-api-con-axios-y-react-js-475o

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To