1.4.1 • Published 6 months ago

@aldoivan10/api-client v1.4.1

Weekly downloads
-
License
MIT
Repository
github
Last release
6 months ago

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

PropiedadTipoDescripción
unknownErrorMsgstringOpcional, mensaje mostrado cuando el error no se reconoce, por defecto: The operation was aborted due an unknown error
timeoutErrorMsgstringOpcional, mensaje mostrado cuando el error es por tiempo de espera terminado, por defecto: The operation was aborted due to timeout
multiReqErrorMsgstringOpcional, 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
abortMultiFetchbooleanOpcional, abortar las peticiones anteriores si ya existe una petición similar, por defecto: true
throwablebooleanOpcional, lanzar errores (funcionamiento de try/catch con await y catch en promise), por defecto: false
headersRecord<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

PropiedadTipoDescripción
urlstringEnd point ó url completa realizar la petición
headers?HeadersInitOpcional, cabeceras de la petición
body?Record<string, any> | FormData | Blob | ArrayBufferOpcional, 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?numberOpcional, tiempo de espera en ms para cancelar la petición, por defecto: 30000 (30s)
identifier?stringOpcional, 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?numberOpcional, 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>

PropiedadTipoDescripción
okbooleanValor que indica si la petición fue exitosa o no. Las respuestas con status 4XX y 5XX son consideradas como no exitosas.
body? TOpcional, 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.
timenumberTiempo en ms de cuantó tardó la petición en realizarse.
retriesnumberNúmero de intentos que se realizarón.
errorErrorOpcional, donde se guarda la información sobre los errores, si la petición ha sido exitosa el atributo no existe.

Error

PropiedadTipoDescripción
statusnumberEstatus de la petición
typestringTipo de error (Not found, Unprocessable Entity, etc)
messagestringDescripció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
1.4.1

6 months ago

1.4.0

6 months ago

1.3.2

7 months ago

1.3.1

7 months ago

1.3.0

7 months ago

1.2.4

7 months ago

1.2.3

7 months ago

1.2.2

7 months ago

1.2.1

7 months ago

1.2.0

7 months ago

1.0.1

8 months ago

1.0.0

8 months ago