Skip to content

Commit ec03e15

Browse files
committed
content: update many things and resolve comments
1 parent cf9635f commit ec03e15

File tree

1 file changed

+89
-44
lines changed

1 file changed

+89
-44
lines changed

content/4.resources/1.learn/1.ofetch-101-first-hand.md

+89-44
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@ modifiedAt: 2023-09-04
1212
layout: learn-post
1313
---
1414

15-
## Introduction
15+
[`ofetch`](https://github.com/unjs/ofetch) is a utility package to make HTTP requests. It exists to unify the API between node, browser and workers and is build on top of the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
1616

17-
`ofetch` is a utility package to make HTTP requests. It exists to unify the API between node, browser and workers.
18-
19-
In fact, Node.js has it's [own fetch](https://undici.nodejs.org/#/) since version 17.5.0 under an experimental flag and [full support at version 18](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#browser_compatibility). If we want to support order version, we will need to use a third party package.
17+
In fact, Node.js [full support the fetch API since version 18](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#browser_compatibility) via the [unidici project](https://github.com/nodejs/undici). If we want to support older version, we will need to use a third party package.
2018

2119
In the same time, we want to be able to fetch in every environment with the same code. Code could start running in a worker and then in a browser.
2220

23-
`ofetch` have been created to simplify these tasks and provide a wrapper around the native fetch API with more options and features.
21+
[`ofetch`](https://github.com/unjs/ofetch) have been created to simplify these tasks and provide a wrapper around the native fetch API with more options and features.
2422

2523
<!-- TODO: add links to /packages/ofetch and to examples (create a component like https://github.com/Barbapapazes/esteban-soubiran.site/blob/main/components/content/GitHubLink.vue -->
2624

@@ -42,30 +40,24 @@ Then, install the package:
4240
npm install ofetch
4341
```
4442

45-
To easily run TypeScript scripts, we can install [jiti](/packages/jiti) as a dev dependency:
46-
47-
```bash
48-
npm install -D jiti
49-
```
50-
51-
<!-- TODO: add link to jiti 101 article -->
43+
::alert{type="info"}
44+
We can use the package manager of our choice like `npm`, `yarn`, `pnpm` or `bun`.
45+
::
5246

5347
## First request
5448

55-
In order to make our first request, let's create a file named `first-request.ts` with the following content:
56-
57-
```ts [first-request.ts]
58-
import { $fetch } from 'ofetch'
49+
In order to make our first request, let's create a file named `first-request.mjs` with the following content:
5950

60-
async function main() {}
51+
```ts [first-request.mjs]
52+
import { ofetch } from 'ofetch'
6153

62-
main().catch(console.error) // Useful to catch errors
54+
const data = await ofetch('https://ungh.cc/repos/unjs/ofetch')
6355
```
6456

6557
Then, we can run the script with:
6658

6759
```bash
68-
jiti first-request.ts
60+
node first-request.mjs
6961
```
7062

7163
And _voilà_, we should see something like this:
@@ -88,17 +80,70 @@ And _voilà_, we should see something like this:
8880
}
8981
```
9082

91-
We have made our first request with ofetch! :tada: Easy, right?
83+
We have made our first request with [`ofetch`](https://github.com/unjs/ofetch)! :tada: Easy, right?
9284

9385
### Manual parsing
9486

95-
<!-- explain the automatic parsing with destr and the fact that you can then control it -->
87+
In our first example, the result return is automatically parsed to JSON thanks to [`unjs/destr`](https://github.com/unjs/destr).
88+
89+
<!-- TODO: add related article to 101 destr -->
90+
91+
This behavior is very useful but sometimes, we want to manually parse the result.
92+
93+
The first way to change how received data is parsed is using the `responseType` option. [`ofetch`](https://github.com/unjs/ofetch) provides several options:
94+
95+
- `text` to have the raw text
96+
- `json` to have a JSON object
97+
- `blob` to have a `Blob` object
98+
- `arrayBuffer` to have an `ArrayBuffer` object
99+
- `stream` to have a `ReadableStream` object
100+
To try it, let's create a new file named `manual-parsing.mjs`.
101+
102+
```ts [manual-parsing.mjs]
103+
import { ofetch } from 'ofetch'
104+
105+
const data = await ofetch('https://ungh.cc/repos/unjs/ofetch', {
106+
responseType: 'blob',
107+
})
108+
109+
console.log(data) // A blob object is returned.
110+
```
111+
112+
We can also provide a custom function to parse the result using the `parseFunction` option. By default [`ofetch`](https://github.com/unjs/ofetch) use [`unjs/destr`](https://github.com/unjs/destr). Let's make our custom parser by creating a new file named `custom-parsing.mjs`.
113+
114+
```ts [custom-parsing.mjs]
115+
import { ofetch } from 'ofetch'
116+
117+
const data = await ofetch('https://ungh.cc/repos/unjs/ofetch', {
118+
parseFunction: (data) => {
119+
return data // We return the raw data but we could use JSON.parse to return a JSON object.
120+
},
121+
})
122+
123+
console.log(data) // The data is not parsed.
124+
```
125+
126+
The function take the raw data as argument and must return something, ideally, data parsed.
96127

97128
## Type safety
98129

99-
Thanks to TypeScript and generics, ofetch can be type safe. Let's see how to do it.
130+
Thanks to TypeScript and generics, [`ofetch`](https://github.com/unjs/ofetch) can be type safe. In order to easily use TypeScript to run our scripts, we will use [`unjs/jiti`](https://github.com/unjs/jiti).
131+
132+
<!-- TODO: add related article to 101 jiti -->
133+
134+
We can install it globally with:
135+
136+
```bash
137+
npm install -g jiti
138+
```
139+
140+
Then, we can run our script with:
141+
142+
```bash
143+
jiti <filename.ts>
144+
```
100145

101-
First, let's create another file called `type-safety.ts`.
146+
Now that we are ready, let's create another file called `type-safety.ts` to type safe our [`ofetch`](https://github.com/unjs/ofetch) request:
102147

103148
```bash
104149
touch type-safety.ts
@@ -116,10 +161,10 @@ interface Repo {
116161
}
117162
```
118163

119-
Now, we can use the `$fetch` function, like in our `first-request.ts` file, but this time, we will add a generic type to it.
164+
Now, we can use the [`ofetch`](https://github.com/unjs/ofetch) function, like in our `first-request.ts` file, but this time, we will add a generic type to it.
120165

121166
```ts [type-safety.ts]
122-
import { $fetch } from 'ofetch'
167+
import { ofetch } from 'ofetch'
123168

124169
interface Repo {
125170
id: number
@@ -130,7 +175,7 @@ interface Repo {
130175
}
131176

132177
async function main() {
133-
const { repo } = await $fetch<{ repo: Repo }>('https://ungh.cc/api/github/unjs/ofetch')
178+
const { repo } = await ofetch<{ repo: Repo }>('https://ungh.cc/api/github/unjs/ofetch')
134179

135180
console.log(`The repo ${repo.name} has ${repo.stars} stars.`) // The repo object is now strongly typed.
136181
}
@@ -146,17 +191,17 @@ This is **not a validation**. It's just a way to tell TypeScript what the respon
146191

147192
## Options
148193

149-
With `ofetch`, we can do much more than simple `GET` requests. Let's see how to use and combine options to make more complex requests.
194+
With [`ofetch`](https://github.com/unjs/ofetch), we can do much more than simple `GET` requests. Let's see how to use and combine options to make more complex requests.
150195

151196
### Methods
152197

153-
`ofetch` supports all the HTTP methods. Let's see how to use one of them. To test a `POST` request, we will use the GitHub API. Let's create a new file named `methods.ts` with the following content:
198+
[`ofetch`](https://github.com/unjs/ofetch) supports all the HTTP methods. Let's see how to use one of them. To test a `POST` request, we will use the GitHub API. Let's create a new file named `methods.ts` with the following content:
154199

155200
```ts [methods.ts]
156-
import { $fetch } from 'ofetch'
201+
import { ofetch } from 'ofetch'
157202

158203
async function main() {
159-
const response = await $fetch('https://api.github.com/gists', {
204+
const response = await ofetch('https://api.github.com/gists', {
160205
method: 'POST',
161206
}) // Be careful, we use the GitHub API.
162207

@@ -183,10 +228,10 @@ Supported methods are:
183228
Of course, when the method is not `GET` or `HEAD`, we can provide a body to the request. Let's see how to do it by creating a new file named `body.ts` with the following content:
184229

185230
```ts [body.ts]
186-
import { $fetch } from 'ofetch'
231+
import { ofetch } from 'ofetch'
187232

188233
async function main() {
189-
const response = await $fetch<string>('https://api.github.com/markdown', {
234+
const response = await ofetch<string>('https://api.github.com/markdown', {
190235
method: 'POST',
191236
// To provide a body, we need to use the `body` option and just use an object.
192237
body: {
@@ -223,13 +268,13 @@ The body can take several formats:
223268

224269
We can also provide some query string parameters to the request. They can be useful to add filters or to paginate the results.
225270

226-
Imagine we want to get the last 2 tags of the `unjs/ofetch` repository. We can do it by creating a new file named `query-string.ts` with the following content:
271+
Imagine we want to get the last 2 tags of the [`unjs/ofetch`](https://github.com/unjs/ofetch) repository. We can do it by creating a new file named `query-string.ts` with the following content:
227272

228273
```ts [query-string.ts]
229-
import { $fetch } from 'ofetch'
274+
import { ofetch } from 'ofetch'
230275

231276
async function main() {
232-
const response = await $fetch('https://api.github.com/repos/unjs/ofetch/tags', {
277+
const response = await ofetch('https://api.github.com/repos/unjs/ofetch/tags', {
233278
query: {
234279
per_page: 2,
235280
},
@@ -279,10 +324,10 @@ We can find a key `params` in the options. It's an alias for `query`.
279324
In the [`methods` section](#methods), we encountered an error because we didn't provide any authentication. With headers, we can solve our problem. In fact, we need to provide to GitHub an authentication token in an header named `Authorization` with a value of `token <token>`. Let's see how to do it by creating a new file named `headers.ts` with the following content:
280325

281326
```ts [headers.ts]
282-
import { $fetch } from 'ofetch'
327+
import { ofetch } from 'ofetch'
283328

284329
async function main() {
285-
const response = await $fetch('https://api.github.com/gists', {
330+
const response = await ofetch('https://api.github.com/gists', {
286331
method: 'POST',
287332
headers: {
288333
Authorization: `token ${process.env.GH_TOKEN}`,
@@ -314,10 +359,10 @@ FetchError: [POST] "https://api.github.com/gists": 422 Unprocessable Entity
314359
And that's a good thing! It means we have successfully authenticated to GitHub. We just need to provide a valid body to the request but now, we know how to do it! We have to add the `body` option to the request with correct data:
315360

316361
```ts [headers.ts]
317-
import { $fetch } from 'ofetch'
362+
import { ofetch } from 'ofetch'
318363

319364
async function main() {
320-
const response = await $fetch('https://api.github.com/gists', {
365+
const response = await ofetch('https://api.github.com/gists', {
321366
method: 'POST',
322367
headers: {
323368
Authorization: `token ${process.env.GH_TOKEN}`,
@@ -353,14 +398,14 @@ Never put credential token directly in code. Use an environment variable instead
353398

354399
### Error handling
355400

356-
This part is straight forward with `ofetch`. Surround the HTTP call with a `try/catch` block and we're done. Let's see how to do it by creating a new file named `error-handling.ts` with the following content:
401+
This part is straight forward with [`ofetch`](https://github.com/unjs/ofetch). Surround the HTTP call with a `try/catch` block and we're done. Let's see how to do it by creating a new file named `error-handling.ts` with the following content:
357402

358403
```ts [error-handling.ts]
359-
import { $fetch } from 'ofetch'
404+
import { ofetch } from 'ofetch'
360405

361406
async function main() {
362407
try {
363-
await $fetch('https://api.github.com', {
408+
await ofetch('https://api.github.com', {
364409
method: 'POST' // This allow us to get an error.
365410
})
366411
}
@@ -402,6 +447,6 @@ We can also completely disable error response using option `ignoreResponseError`
402447

403448
## Conclusion
404449

405-
We have seen how to use `ofetch` to easily make HTTP requests in any environment. We have seen how to use the different options to make more complex requests and how to gracefully handle errors.
450+
We have seen how to use [`ofetch`](https://github.com/unjs/ofetch) to easily make HTTP requests in any environment. We have seen how to use the different options to make more complex requests and how to gracefully handle errors.
406451

407-
With this 101, we've just scratch the surface of `ofetch`. In next articles, we will use some advanced options like `retry` and `timeout` to make our requests more robust, interceptors to make optimistic updates and how to create a fetch with some default options!
452+
With this 101, we've just scratch the surface of [`ofetch`](https://github.com/unjs/ofetch). In next articles, we will use some advanced options like `retry` and `timeout` to make our requests more robust, interceptors to make optimistic updates and how to create a fetch with some default options!

0 commit comments

Comments
 (0)