@aldoivan10/api-client v1.4.1
ApiClient
ApiClient es una clase para realizar solicitudes HTTP utilizando un enfoque simple y extensible. Compatible con métodos como GET
, POST
, PUT
, PATCH
y DELETE
. También permite registrar y eliminar eventos asociados a solicitudes HTTP.
📦 Instalación
npm i @aldoivan10/api-client
pnpm add @aldoivan10/api-client
📖 Uso
Se debe crear una instancia ApiClient
para poder hacer uso de sus funciones, donde opcionalmente se puede definir una url base para posteriormente únicamente pasar los end points.
💡 Constructor
El constructor se compone de 2 partes, baseUrl
es el dominio o root a donde se harán las peticiones para evitar repetirla y options
que son opciones base que indican el funcionamiento de la clase.
ApiClient(baseUrl?: string, options?: Constructor)
Constructor
Propiedad | Tipo | Descripción |
---|---|---|
unknownErrorMsg | string | Opcional, mensaje mostrado cuando el error no se reconoce, por defecto: The operation was aborted due an unknown error |
timeoutErrorMsg | string | Opcional, mensaje mostrado cuando el error es por tiempo de espera terminado, por defecto: The operation was aborted due to timeout |
multiReqErrorMsg | string | Opcional, mensaje mostrado cuando el error es porque se repitio una peticion sin que haya terminado, por defecto: The operation has been cancelled because another identical request has been made |
abortMultiFetch | boolean | Opcional, abortar las peticiones anteriores si ya existe una petición similar, por defecto: true |
throwable | boolean | Opcional, lanzar errores (funcionamiento de try/catch con await y catch en promise), por defecto: false |
headers | Record<string, string> | Opcional, headers por defecto. Se pueden agregar posteriormente usando addHeader |
Ejemplo
import { ApiClient } from "@aldoivan10/api-client"
const client = new ApiClient("https://jsonplaceholder.typicode.com") // ó new ApiClient() simplemente
// Agregar evento
client.on("POST", (response) => {
if (response.ok) {
// Actualizar UI
}
})
const posts = await client.get({ url: "/posts" })
console.log(posts)
/*
{
ok: true,
time: 252,
body: [
{
userId: 1,
id: 1,
title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
body: 'quia et suscipit\n' +
'suscipit recusandae consequuntur expedita et cum\n' +
'reprehenderit molestiae ut ut quas totam\n' +
'nostrum rerum est autem sunt rem eveniet architecto'
}, ...
]
}
*/
const add = await client.post({
url: "/posts",
body: { title: "Great programmer", body: "Aldoivan10", userId: 1 },
})
console.log(add)
/*
{
ok: true,
time: 161,
body: { title: 'Grat programmer', body: 'Aldoivan10', userId: 1, id: 101 }
}
*/
const error = await client.post({
url: "/posts",
body: { title: "Grat programmer", body: "Aldoivan10", userId: 1 },
timeout: 0,
retries: 3,
})
console.log(error)
/*
{
ok: false,
time: 13,
retries: 3,
error: {
status: 500,
type: 'TimeoutError',
message: 'The operation was aborted due to timeout',
body: null
}
}
*/
const serverError = await client.put({
url: "/posts",
body: {},
})
console.log(serverError)
/*
{
ok: false,
time: 163,
error: {
status: 404,
type: 'Not Found',
body: {},
message: 'Error desconocido'
}
}
*/
/* ERRORES */
const multiFetch = new ApiClient("https://httpstat.us")
multiFetch
.get({ url: "/200", timeout: 500, body: { sleep: 8000 } })
.then((res) => {
console.log(res)
})
const res = await multiFetch.get({ url: "/200", body: { sleep: 500 } })
console.log(res)
/*
First:
{
ok: false,
time: 3,
retries: 1,
error: {
status: 500,
type: 'MultiRequestError',
message: 'The operation has been cancelled because another identical request has been made',
body: null
}
}
Then:
{ ok: true, time: 738, body: '200 OK', retries: 1 }
*/
/* POR THROWING */
const throwable = new ApiClient("https://httpstat.us", { throwable: true })
throwable
.get({ url: "/200", timeout: 500, body: { sleep: 8000 } })
.then((res) => {
console.log(res)
})
.catch((error) => {
console.log("Error by throwing:")
console.log(error)
})
/*
Error by throwing:
{
ok: false,
time: 512,
retries: 1,
error: {
status: 500,
type: 'TimeoutError',
message: 'The operation was aborted due to timeout',
body: null
}
*/
const throwableAwait = new ApiClient("https://httpstat.us", {
throwable: true,
})
try {
setTimeout(() => throwableAwait.abort("GET-200", "Prueba de abort"), 500)
await throwableAwait.get({ url: "/200", body: { sleep: 8000 } })
} catch (error) {
console.log("Error por try/catch")
console.log(error)
}
/*
Error por try/catch
{
ok: false,
time: 505,
retries: 1,
error: {
status: 500,
type: 'UserAbort',
message: 'Prueba de abort',
body: null
}
}
*/
📚 Métodos disponibles
GET
get<T>(options: Options): Promise<Response<T>>
POST
post<T>(options: Options): Promise<Response<T>>
PATCH
patch<T>(options: Options): Promise<Response<T>>
PUT
put<T>(options: Options): Promise<Response<T>>
DELETE
delete<T>(options: Options): Promise<Response<T>>
REQUEST
Petición genérica para funcionar dinámicamente.
request<T>(method: Method, options: Options): Promise<Response<T>>
ABORT
Cancela la solicitud por su llave, se puede pasar su identifier
, en automático la llave es method
+identifier
, ej: GET-posts
.
abort(key: string, reason?: string): void
ADD HEADER
Agrega un header por defecto, útil para tokens de autenticación, etc.
addHeader(key: string, value: string): void
REMOVE HEADER
Elimina un header por defecto.
removeHeader(key: string): void
👀 Eventos
Adicionalmente, además de obtener la información mediante los típicos métodos (GET, POST, etc), se pueden registrar eventos para ejecutar acciones adicionales cada que se realiza una solicitud.
on(method: Method, event: Event): void
También pueden ser eliminados mediante:
removeEvent(method: Method, event: Event): void
📋 API
Options
Propiedad | Tipo | Descripción |
---|---|---|
url | string | End point ó url completa realizar la petición |
headers? | HeadersInit | Opcional, cabeceras de la petición |
body? | Record<string, any> | FormData | Blob | ArrayBuffer | Opcional, cuerpo de la petición. Si la petición es de tipo GET y el body es un Record, el body se convertirá en Query Params. Si el body es un Record, el header Content-type será application/json (Se puede reemplazar mandando el header en los parámetros) |
tiemout? | number | Opcional, tiempo de espera en ms para cancelar la petición, por defecto: 30000 (30s) |
identifier? | string | Opcional, identificador que se le dará a la petición, primero se usará el método GET \| PUT \| PATCH \| DELETE , posteriormente el identificador separados por - , si no se proporciona un identificador en automático se asignara el endpoint dado omitiendo query params y reemplazando / por - , ejemplo: GET-products-123 , si el end point fue /products/123 , si se pasa custom-identifier , quedaría GET-custom-identifier |
retries? | number | Opcional, número de intetos (solo para timeout), por defecto: 1 |
...options? | Record<string, any> | Opcional, opciones extra que acepta RequestInit para la petición |
Response <T>
Propiedad | Tipo | Descripción |
---|---|---|
ok | boolean | Valor que indica si la petición fue exitosa o no. Las respuestas con status 4XX y 5XX son consideradas como no exitosas. |
body? | T | Opcional, donde se guarda el resultado de la petición si es que ha sido exitosa, caso contrario el atributo no existe. La respuesta se tratará de convertir en JSON, caso contrario se obtendrá el texto. |
time | number | Tiempo en ms de cuantó tardó la petición en realizarse. |
retries | number | Número de intentos que se realizarón. |
error | Error | Opcional, donde se guarda la información sobre los errores, si la petición ha sido exitosa el atributo no existe. |
Error
Propiedad | Tipo | Descripción |
---|---|---|
status | number | Estatus de la petición |
type | string | Tipo de error (Not found, Unprocessable Entity, etc) |
message | string | Descripción del error |
| body | null | Record<string, any> | Cuerpo que fue enviado a la petición |
Method
type Method = "GET" | "POST" | "PUT" | "PATCH" | "DELETE"
Event
type Event = (response: Response<T>) => void