Gathering detailed insights and metrics for @bylg/fetcher
Gathering detailed insights and metrics for @bylg/fetcher
npm install @bylg/fetcher
Typescript
Module System
Node Version
NPM Version
70.7
Supply Chain
98.9
Quality
78.1
Maintenance
100
Vulnerability
100
License
TypeScript (100%)
Total Downloads
5,059
Last Day
45
Last Week
118
Last Month
251
Last Year
2,913
1 Stars
59 Commits
1 Watching
1 Branches
1 Contributors
Minified
Minified + Gzipped
Latest Version
0.3.2
Package Id
@bylg/fetcher@0.3.2
Unpacked Size
23.29 kB
Size
5.67 kB
File Count
7
NPM Version
10.2.4
Node Version
18.19.1
Publised On
05 Mar 2024
Cumulative downloads
Total Downloads
Last day
0%
45
Compared to previous day
Last week
306.9%
118
Compared to previous week
Last month
33.5%
251
Compared to previous month
Last year
35.7%
2,913
Compared to previous year
1
6
BYLG Fetcher is a small wrapper around fetch and Zod. It allows you to predefine headers and context and have a type-safe response.
A FetcherClient instance provides two methods, fetcher and combineFetchers, that are used to define and combine fetcher functions respectively. A fetcher function could be an asynchronous function that makes requests to a remote server and returns a typed response.
1npm install @bylg/fetcher 2yarn add @bylg/fetcher 3pnpm add @bylg/fetcher
Zod is a peer dependency, so you will need to install that as well.
1npm install zod 2yarn add zod 3pnpm add zod
You can create a new instance of the FetcherClient by passing it a context schema and headers schema. You can then use the fetcher and combineFetchers methods to define and combine fetcher functions respectively.
1import { FetcherClient } from "@bylg/fetcher"; 2import { z } from "zod"; 3 4const f = new FetcherClient({ 5 ctx: z.string().url(), // Define the context schema 6 headers: { 7 Authorization: z.string().min(1), // Define the headers schema 8 }, 9}); 10 11// Define a fetcher function 12const getTodo = f.fetcher(({ ctx, headers, get, post }, id: string) => { 13 const url = `${ctx}/todos/${id}`; // Use the context 14 const schema = z.string(); // Define the response schema 15 const options = {}; // Define the request options. Headers are automatically added. 16 return get(url, schema, options); 17}); 18 19// Define a fetcher function 20const createTodo = f.fetcher(({ ctx, post }, content: string) => { 21 const url = `${ctx}/todos`; // Use the context 22 const schema = z.object({ 23 id: z.string(), 24 content: z.string(), 25 }); // Define the response schema 26 const data = { content }; // Define the data to be sent in the request body 27 const options = {}; // Define the request options. Headers are automatically added. 28 return post(url, schema, data, options); 29}); 30 31// Combine the fetcher functions 32const createTodoFetcher = f.combineFetchers({ 33 getTodo, 34 createTodo, 35}); 36 37// Define the context and headers 38// Alternatively, you can use a function that returns the context and headers 39const todoFetcher = createTodoFetcher({ 40 ctx: "https://example.com", // The type of ctx is inferred from the context schema 41 headers: { Authorization: "some-token" }, // The type of headers is inferred from the headers schema 42}); 43 44// Call the fetcher functions 45const todo = await todoFetcher.getTodo("1"); 46// ^? (property) getTodo: (input: string) => Promise<string> 47const newTodo = await todoFetcher.createTodo({ content: "test" }); 48// ^? (property) createTodo: (input: string) => Promise<{ id: string; content: string; }>
Above code defines context and headers schemas and creates a FetcherClient
instance with them. Two fetcher functions are defined using the fetcher
method, and then combined using the combineFetchers
method.
Now you can use it in React Query:
1import { useQuery } from "react-query"; 2import { todoFetcher } from "path/to/todoFetcher"; 3 4const Todo = ({ id }) => { 5 const { data, isLoading, error } = useQuery(["todo", id], () => 6 todoFetcher.getTodo(id) 7 ); 8 9 if (isLoading) return <div>Loading...</div>; 10 if (error) return <div>Error: {error.message}</div>; 11 return <div>{data}</div>; 12};
1import { useMutation } from "react-query"; 2import { todoFetcher } from "path/to/todoFetcher"; 3 4const TodoForm = () => { 5 const [content, setContent] = useState(""); 6 const { mutate, isLoading, error } = useMutation(todoFetcher.createTodo); 7 8 const handleSubmit = () => { 9 e.preventDefault(); 10 mutate({ content }); 11 }; 12 13 if (isLoading) return <div>Loading...</div>; 14 if (error) return <div>Error: {error.message}</div>; 15 return ( 16 <form onSubmit={handleSubmit}> 17 <input value={content} onChange={(e) => setContent(e.target.value)} /> 18 <button type="submit">Create</button> 19 </form> 20 ); 21};
postProcess
to refresh token1const f = new FetcherClient({ 2 ctx: z.object({ 3 url: z.string().url(), 4 refreshToken: z.string(), 5 }), 6 headers: { 7 Authorization: z.string().min(1), 8 }, 9}); 10 11const getTodo = f.fetcher(async ({ ctx, get }, id: string) => { 12 const { data, response } = await get( 13 `${ctx.url}/todos/${id}`, 14 z.union([z.object({ code: z.string() }), z.string()]) 15 ); 16 if ( 17 response.status === 401 && 18 typeof data === "object" && 19 "code" in data && 20 data.code === "token-expired" 21 ) { 22 // throw error to trigger onError 23 throw new Error(data.code); 24 } 25 return { data, response }; 26}); 27 28const createFetchers = f.combineFetchers({ 29 getTodo, 30}); 31 32let token = "old-token"; 33const refreshTokensRetryCounts = new Map<string, number>(); 34 35const fetchers = createFetchers(() => ({ 36 ctx: { url: "https://example.com", refreshToken: "refresh-token" }, 37 headers: { Authorization: token }, 38 postProcess: { 39 // when your fetcher throw an error, it will call this function with the error and original fetcher function and input 40 onError: async ({ options, input, error, fetcher, fetcherName }) => { 41 if (refreshTokensRetryCounts.get(fetcherName) === 2) { 42 throw new Error(`Refresh token failed when calling: ${fetcherName}`); 43 } 44 // if the error is token expired, we will refresh the token and retry the original fetcher 45 if (error instanceof Error && error.message === "token-expired") { 46 refreshTokensRetryCounts.set( 47 fetcherName, 48 (refreshTokensRetryCounts.get(fetcherName) ?? 0) + 1 49 ); 50 // get new token and update token 51 token = await refreshTokens(options.ctx.refreshToken); 52 await fetcher(options, input as any); 53 } 54 return; 55 }, 56 }, 57})); 58 59await fetchers.getTodo("1");
No vulnerabilities found.
No security vulnerabilities found.