Skip to content

Commit

Permalink
feat: added new learn section with fetch examples (#7499)
Browse files Browse the repository at this point in the history
* feat: added new learn section with fetch examples

#7492

* updated code example and added to sidebar

* docs: updated example code

* docs: Updated example to use mistral and typo fix

* docs: spelling
  • Loading branch information
benhalverson authored Feb 24, 2025
1 parent 7a73ed0 commit 8f8f028
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 0 deletions.
4 changes: 4 additions & 0 deletions apps/site/navigation.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@
"link": "/learn/getting-started/profiling",
"label": "components.navigation.learn.gettingStarted.links.profiling"
},
"fetch": {
"link": "/learn/getting-started/fetch",
"label": "components.navigation.learn.gettingStarted.links.fetch"
},
"securityBestPractices": {
"link": "/learn/getting-started/security-best-practices",
"label": "components.navigation.learn.gettingStarted.links.securityBestPractices"
Expand Down
181 changes: 181 additions & 0 deletions apps/site/pages/en/learn/getting-started/fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
---
title: Node.js Fetch
layout: learn
authors: benhalverson, LankyMoose
---

# Using the Fetch API with Undici in Node.js

## Introduction

[Undici](https://undici.nodejs.org) is an HTTP client library that powers the fetch API in Node.js. It was written from scratch and does not rely on the built-in HTTP client in Node.js. It includes a number of features that make it a good choice for high-performance applications.

## Basic GET Usage

```js
async function main() {
// Like the browser fetch API, the default method is GET
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await response.json();
console.log(data);
// returns something like:
// {
// 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'
// }
}

main().catch(console.error);
```

## Basic POST Usage

```js
// Data sent from the client to the server
const body = {
title: 'foo',
body: 'bar',
userId: 1,
};

async function main() {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'User-Agent': 'undici-stream-example',
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
const data = await response.json();
console.log(data);
// returns something like:
// { title: 'foo', body: 'bar', userId: 1, id: 101 }
}

main().catch(console.error);
```

## Customizing the Fetch API with Undici

Undici allows you to customize the Fetch API by providing options to the `fetch` function. For example, you can set custom headers, set the request method, and set the request body. Here is an example of how you can customize the Fetch API with Undici:

The [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) function takes two arguments: the URL to fetch and an options object. The options object is the [Request](https://undici.nodejs.org/#/docs/api/Dispatcher?id=parameter-requestoptions) object that you can use to customize the request. The function returns a [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) that resolves to a [Response](https://undici.nodejs.org/#/docs/api/Dispatcher?id=parameter-responsedata) object. One difference between the Fetch API in the browser and the Fetch API in Node.js is that the Node.js version does not support

In the following example, we are sending a POST request to the Ollama API with a JSON payload. Ollama is a cli tool that allows you to run LLM's (Large Language Models) on your local machine. You can download it [here](https://ollama.com/download)

```bash
ollama run mistral
```

This will download the `mistral` model and run it on your local machine.

With a pool, you can reuse connections to the same server, which can improve performance. Here is an example of how you can use a pool with Undici:

```js
import { Pool } from 'undici';

const ollamaPool = new Pool('http://localhost:11434', {
connections: 10,
});

/**
* Stream the completion of a prompt using the Ollama API.
* @param {string} prompt - The prompt to complete.
* @link https://github.com/ollama/ollama/blob/main/docs/api.md
**/
async function streamOllamaCompletion(prompt) {
const { statusCode, body } = await ollamaPool.request({
path: '/api/generate',
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt, model: 'mistral' }),
});

// You can read about HTTP status codes here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
// 200 means the request was successful.
if (statusCode !== 200) {
throw new Error(`Ollama request failed with status ${statusCode}`);
}

let partial = '';

const decoder = new TextDecoder();
for await (const chunk of body) {
partial += decoder.decode(chunk, { stream: true });
console.log(partial);
}

console.log('Streaming complete.');
}

try {
await streamOllamaCompletion('What is recursion?');
} catch (error) {
console.error('Error calling Ollama:', error);
} finally {
console.log('Closing Ollama pool.');
ollamaPool.close();
}
```

## Streaming Responses with Undici

[Streams](https://nodejs.org/docs/v22.14.0/api/stream.html#stream) is a feature in Node.js that allows you to read and write chucks of data.

```js
import { stream } from 'undici';
import { Writable } from 'stream';

async function fetchGitHubRepos() {
const url = 'https://api.github.com/users/nodejs/repos';

const { statusCode } = await stream(
url,
{
method: 'GET',
headers: {
'User-Agent': 'undici-stream-example',
Accept: 'application/json',
},
},
() => {
let buffer = '';

return new Writable({
write(chunk, encoding, callback) {
buffer += chunk.toString();

try {
const json = JSON.parse(buffer);
console.log(
'Repository Names:',
json.map(repo => repo.name)
);
buffer = '';
} catch (error) {
console.error('Error parsing JSON:', error);
}

callback();
},
final(callback) {
console.log('Stream processing completed.');
callback();
},
});
}
);

console.log(`Response status: ${statusCode}`);
}

fetchGitHubRepos().catch(console.error);
```
1 change: 1 addition & 0 deletions packages/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"nodejsWithWebassembly": "Node.js with WebAssembly",
"debugging": "Debugging Node.js",
"profiling": "Profiling Node.js Applications",
"fetch": "Fetching data with Node.js",
"securityBestPractices": "Security Best Practices"
}
},
Expand Down

0 comments on commit 8f8f028

Please sign in to comment.