Skip to content

Commit 9900045

Browse files
authored
Better Fetch React & Typed Routes (#1)
* feat: react hooks * docs: react doc added on the readme * feat: typed routes and tests
1 parent 581f022 commit 9900045

17 files changed

+1022
-243
lines changed

.github/workflows/ci.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,20 @@ jobs:
2222
run: bun typecheck
2323

2424
- name: Test
25-
run: bun test
25+
run: bun run test
26+
release:
27+
name: release
28+
needs: test
29+
if: ${{ !contains(github.event.head_commit.message, 'skip ci') && !contains(github.event.head_commit.message, 'skip release') && github.event_name != 'pull_request' }}
30+
runs-on: ubuntu-latest
31+
steps:
32+
- name: Checkout repo
33+
uses: actions/checkout@v4
34+
35+
- uses: ./.github/setup
36+
- run: bun run release
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
40+
41+

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,11 @@
5858

5959
### ❤️ Contributors
6060

61-
- Bekacru <[email protected]>
61+
- Bekacru <[email protected]>
62+
63+
## v.1.2.0
64+
65+
### 🚀 Release
66+
67+
- typed routes. Now you can create typed routes with betterFetch.
68+
- custom fetch implementation now supports node-fetch

README.md

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
# Better Fetch
22

3-
A fetch wrapper for typescript that returns data and error object. Works on the browser, node (version 18+), workers, deno and bun. Some of the APIs are inspired by [ofetch](https://github.com/unjs/ofetch).
3+
A fetch wrapper for typescript that returns data and error object, supports defined route schemas, plugins and more. Works on the browser, node (version 18+), workers, deno and bun.
44

55
## Installation
66

77
```bash
88
pnpm install @better-tools/fetch
99
```
1010

11-
## Usage
11+
## Basic Usage
1212

1313
```typescript
14-
import fetch from "@better-tools/fetch"
14+
import betterFetch from "@better-tools/fetch"
1515

16-
const { data, error } = await fetch<{
16+
const { data, error } = await betterFetch<{
1717
userId: number;
1818
id: number;
1919
title: string;
@@ -47,12 +47,52 @@ const { data, error } = await $fetch<{
4747
}>("/todos/1");
4848
```
4949

50+
### ♯ Typed Fetch
51+
52+
Better fetch allows you to define schema that will be used to infer request body, query parameters, response data and error types.
53+
54+
```typescript
55+
import { createFetch } from "@better-tools/fetch";
56+
import { T, FetchSchema } from "@better-tools/fetch/typed";
57+
58+
const routes = {
59+
"/": {
60+
output: T.Object({
61+
message: T.String(),
62+
}),
63+
},
64+
"/signin": {
65+
input: T.Object({
66+
username: T.String(),
67+
password: T.String(),
68+
}),
69+
output: T.Object({
70+
token: T.String(),
71+
}),
72+
},
73+
"/signup": {
74+
input: T.Object({
75+
username: T.String(),
76+
password: T.String(),
77+
optional: T.Optional(T.String()),
78+
}),
79+
output: T.Object({
80+
message: T.String(),
81+
}),
82+
},
83+
} satisfies FetchSchema;
84+
85+
const $fetch = createFetch<typeof routes>()
86+
```
87+
88+
5089
You can also pass default response and error types. Which will be used if you don't pass the types in the fetch call.
5190

5291
```typescript
5392
import { createFetch } from "@better-tools/fetch";
93+
import { DefaultSchema } from "@better-tools/fetch/typed";
5494

55-
const $fetch = createFetch<{
95+
const $fetch = createFetch<DefaultSchema,{
5696
userId: number;
5797
id: number;
5898
title: string;
@@ -75,6 +115,83 @@ const { data, error } = await $fetch<{
75115
//data and error types are inferred from fetch call
76116
```
77117

118+
119+
### ♯ Using with React
120+
To use better fetch with React hooks, you have the option to import createReactFetch. This allows you to create hooks with custom defaults. Alternatively, you can directly import each individual hook.
121+
122+
123+
With createReactFetch, you can create hooks with custom defaults.
124+
```typescript
125+
import { createReactFetch } from "@better-tools/fetch/react";
126+
127+
//create hooks with custom defaults
128+
const { useFetch, useMutate } = createReactFetch({
129+
baseUrl: "https://jsonplaceholder.typicode.com",
130+
retry: 2,
131+
});
132+
133+
function App() {
134+
type Todo = {
135+
userId: number;
136+
id: number;
137+
title: string;
138+
completed: boolean;
139+
};
140+
const { data, error, isPending } = useFetch<Todo>("/todos/1");
141+
if (error) {
142+
// handle the error
143+
}
144+
if (data) {
145+
// handle the data
146+
}
147+
const { mutate, isPending } = useMutate<Todo>("/todos")
148+
await mutate({
149+
userId: 1,
150+
id: 1,
151+
title: "delectus aut autem",
152+
completed: false
153+
})
154+
}
155+
```
156+
157+
Alternatively, you can directly import each individual hook.
158+
```typescript
159+
import { useFetch, useMutate } from "@better-tools/fetch/react";
160+
161+
function App() {
162+
const { data, error } = useFetch<{
163+
userId: number;
164+
id: number;
165+
title: string;
166+
completed: boolean;
167+
}>("https://jsonplaceholder.typicode.com/todos/1");
168+
if (error) {
169+
// handle the error
170+
}
171+
if (data) {
172+
// handle the data
173+
}
174+
}
175+
```
176+
177+
178+
### ♯ Plugins
179+
180+
Plugins are functions that can be used to modify the request, response, error and other parts of the request lifecycle.
181+
182+
Example:
183+
```typescript
184+
import { createFetch } from "@better-tools/fetch";
185+
import { csrfProtection } from "./plugins/csrfProtection"
186+
187+
const $fetch = createFetch({
188+
baseUrl: "https://jsonplaceholder.typicode.com",
189+
retry: 2,
190+
plugins: [csrfProtection()]
191+
});
192+
```
193+
194+
78195
### ♯ Parsing the response
79196

80197
Better fetch will smartly parse JSON using JSON.parse and if it fails it will return the response as text.

biome.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
},
1616
"suspicious": {
1717
"noExplicitAny": "off"
18+
},
19+
"style": {
20+
"noParameterAssign": "off"
1821
}
1922
}
2023
}

bun.lockb

76.6 KB
Binary file not shown.

package.json

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,53 @@
11
{
22
"name": "@better-tools/fetch",
3-
"version": "1.1.5",
3+
"version": "1.2.0",
44
"packageManager": "[email protected]",
55
"main": "./dist/index.cjs",
66
"module": "./dist/index.js",
77
"react-native": "./dist/index.js",
88
"types": "./dist/index.d.ts",
99
"devDependencies": {
10+
"@happy-dom/global-registrator": "^14.7.1",
11+
"@testing-library/react": "^15.0.3",
1012
"@types/bun": "^1.1.0",
1113
"@types/node": "^20.11.30",
14+
"@types/react": "^18.2.79",
1215
"biome": "^0.3.3",
16+
"react": "^18.2.0",
1317
"tsup": "^8.0.2",
14-
"typescript": "^5.4.5"
18+
"typescript": "^5.4.5",
19+
"h3": "^1.11.1",
20+
"@sinclair/typebox": "^0.32.27",
21+
"@testing-library/dom": "^10.0.0",
22+
"global-jsdom": "^24.0.0",
23+
"jsdom": "^24.0.0",
24+
"listhen": "^1.7.2",
25+
"mocha": "^10.4.0",
26+
"react-dom": "^18.2.0",
27+
"vitest": "^1.5.0"
1528
},
1629
"exports": {
1730
".": {
1831
"import": "./dist/index.js",
1932
"require": "./dist/index.cjs"
33+
},
34+
"./typed": {
35+
"import": "./dist/typed.js",
36+
"require": "./dist/typed.cjs",
37+
"types": "./dist/typed.d.ts"
38+
},
39+
"./react": {
40+
"import": "./dist/react.js",
41+
"require": "./dist/react.cjs",
42+
"types": "./dist/react.d.ts"
2043
}
2144
},
2245
"scripts": {
2346
"build": "tsup",
47+
"test": "vitest run",
48+
"test:watch": "vitest watch",
2449
"lint": "biome check .",
25-
"release": "bun run build && npm publish --access public",
50+
"release": "bun run build && npm publish",
2651
"lint:fix": "biome check . --apply",
2752
"typecheck": "tsc --noEmit"
2853
},

0 commit comments

Comments
 (0)