From 6585ae027e5c89236375a7e69ec3827d7c8b1d34 Mon Sep 17 00:00:00 2001 From: Frangeris Peguero Date: Fri, 4 Oct 2024 21:52:44 -0300 Subject: [PATCH] fix: Various fixes (#11) * Fixed issue with empty URLs and Response methods not available * Update test with correct values * Fixed bad import on readme * Added package description to npm * Return data key only if exists * Update readme.md * Improve readme.md guide --- README.md | 21 ++++++++++++++---- __tests__/service.spec.ts | 2 +- package.json | 1 + src/service.ts | 46 ++++++++++++++++++++++++--------------- src/types.ts | 2 +- 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index fff38cd..f482aba 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ By setting up this initialization, you ensure that every request you make using Once the module is initialized, you can easily make requests to the defined endpoints. Here's a snippet for requests: ```ts -import { useRequests, init } from "./src"; +import { useRequests, init } from "use-requests"; type User = {}; @@ -90,13 +90,28 @@ init("https://api.example.io/dev", { ...Api }); const main = async () => { const { userById, users } = useRequests(); const { data: usersRes } = await users.get(); - const { data: userByIdRes } = await userById.get({ params: { id: 1 } }); + const { + data: userByIdRes, // wrapper that cast to generic + + // properties available from Response web API + json, + ok, + body, + blob, + bytes, + headers, + status, + text, + statusText, + } = await userById.get({ params: { id: 1 } }); // Optionally, set headers for the request // users.headers.set("Authorization", "Bearer token"); }; main(); ``` +The `data` property is a wrapper around the `Response.json()` method that looks for `data` key in the response, in case that property exists, it will be returned as the representation of the response `body.data` casted to the generic type used, eg: `User[]` or `User`. + The test endpoint is accessed with an id parameter. You can also set headers (like authorization tokens) as needed. --- @@ -118,8 +133,6 @@ Each method returned by `useRequests` is type-safe, meaning that the parameters The response by any methods is an instance of [fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object, which you can use to extract the data, status, headers, etc. -The `data` property is a wrapper around the `Response.json()` method, which returns a promise that resolves to the JSON representation of the response body casted to the generic type used, eg: `User[]` or `User`. - > [!WARNING] > Any parameters defined in the endpoint definition are required when calling the method. If you omit a required parameter, TypeScript will throw a compile-time error or an exception will be thrown at runtime. diff --git a/__tests__/service.spec.ts b/__tests__/service.spec.ts index edf3b56..64cc2cb 100644 --- a/__tests__/service.spec.ts +++ b/__tests__/service.spec.ts @@ -15,7 +15,7 @@ describe("service", () => { describe("build", () => { it("should return empty string if no path is provided", () => { const service = new Service("/resource"); - expect(service["build"]()).toBe(""); + expect(service["build"]()).toBe("/resource"); }); it("should return the path if a string path is provided", () => { diff --git a/package.json b/package.json index 50a79bd..959c83e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "use-requests", + "description": "Type-Safe HTTP client hook (react) to handle requests based on native fetch api with some magic under the hood ✨", "version": "1.0.8", "author": "Frangeris Peguero ", "license": "MIT", diff --git a/src/service.ts b/src/service.ts index b4707eb..333a143 100644 --- a/src/service.ts +++ b/src/service.ts @@ -34,16 +34,16 @@ export class Service

{ } private build(path?: RequestPath

) { - if (!path) { - return ""; - } - if (typeof path === "string") { return path; } - // build complex path let url = this.resource; + if (!path) { + return url; + } + + // build complex path const { params, query } = path; if (params) { for (const k in params) { @@ -63,24 +63,33 @@ export class Service

{ return url; } - private async response(request: Response): ServiceResponse { - return { - ...request, - data: (await request.json()) as T, - }; + private async response(res: Response): Promise> { + const newRes = res.clone() as unknown as ServiceResponse; + + if (res.ok) { + const body = await res.json(); + if (body?.data) { + newRes.data = body.data as T; + } + } + + return newRes; } // HTTP methods - async get(path?: RequestPath

): ServiceResponse { - const request = await this.request({ + async get(path?: RequestPath

) { + const response = await this.request({ path, method: "get", }); - return this.response(request); + return this.response(response); } - async post(payload: any, path?: RequestPath

): ServiceResponse { + async post( + payload: any, + path?: RequestPath

+ ): Promise> { const request = await this.request({ path, method: "post", @@ -90,7 +99,10 @@ export class Service

{ return this.response(request); } - async put(payload: any, path?: RequestPath

): ServiceResponse { + async put( + payload: any, + path?: RequestPath

+ ): Promise> { const request = await this.request({ path, method: "put", @@ -100,7 +112,7 @@ export class Service

{ return this.response(request); } - async delete(path?: RequestPath

): ServiceResponse { + async delete(path?: RequestPath

): Promise> { const request = await this.request({ path, method: "delete", @@ -112,7 +124,7 @@ export class Service

{ async patch( ops: PatchOperation[], path?: RequestPath

- ): ServiceResponse { + ): Promise> { const request = await this.request({ path, method: "patch", diff --git a/src/types.ts b/src/types.ts index 2c08874..a15d4d9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,7 +7,7 @@ export type InitOptions = { export type Services = { [K in keyof T]: Service }; -export type ServiceResponse = Promise; +export type ServiceResponse = { data: R } & Response; export type RequestPath

= | {