From d331984c27c1cd2c40e862246a795b1c481530ac Mon Sep 17 00:00:00 2001 From: James Crosby Date: Thu, 26 Oct 2023 11:53:11 +0100 Subject: [PATCH 1/3] Add request examples. --- README.md | 2 +- examples/README.md | 98 +++++++++++++++++++++++++++++++++++++++++++++ examples/request.js | 80 ++++++++++++++++++++++++++++++++++-- test/examples.js | 46 +++++++++++++++++++++ 4 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 examples/README.md create mode 100644 test/examples.js diff --git a/README.md b/README.md index 3ba89890df6..e81d1aae80b 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Returns a promise with the result of the `Dispatcher.request` method. Calls `options.dispatcher.request(options)`. -See [Dispatcher.request](./docs/api/Dispatcher.md#dispatcherrequestoptions-callback) for more details. +See [Dispatcher.request](./docs/api/Dispatcher.md#dispatcherrequestoptions-callback) for more details, and [request examples](./examples/README.md) for examples. ### `undici.stream([url, options, ]factory): Promise` diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000000..c8051344559 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,98 @@ + +## undici.request() examples + +### A simple GET request, read the response body as text: +```js +const { request } = require('undici') +async function getRequest (port = 3001) { + // A simple GET request + const { + statusCode, + headers, + body + } = await request(`http://localhost:${port}/`) + + const data = await body.text() + console.log('response received', statusCode) + console.log('headers', headers) + console.log('data', data) +} +``` + +### A JSON POST request, read the response body as json: +```js +const { request } = require('undici') +async function postJSONRequest (port = 3001) { + const requestBody = { + hello: 'JSON POST Example body' + } + + const { + statusCode, + headers, + body + } = await request( + `http://localhost:${port}/json`, + { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(requestBody) } + ) + + // .json() will fail if we did not receive a valid json body in response: + const decodedJson = await body.json() + console.log('response received', statusCode) + console.log('headers', headers) + console.log('data', decodedJson) +} +``` + +### A Form POST request, read the response body as text: +```js +const { request } = require('undici') +async function postFormRequest (port = 3001) { + // Make a URL-encoded form POST request: + const qs = require('querystring') + + const requestBody = { + hello: 'URL Encoded Example body' + } + + const { + statusCode, + headers, + body + } = await request( + `http://localhost:${port}/form`, + { method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: qs.stringify(requestBody) } + ) + + const data = await body.text() + console.log('response received', statusCode) + console.log('headers', headers) + console.log('data', data) +} +``` + +### A DELETE request +```js +const { request } = require('undici') +async function deleteRequest (port = 3001) { + // Make a DELETE request + const { + statusCode, + headers, + body + } = await request( + `http://localhost:${port}/something`, + { method: 'DELETE' } + ) + + console.log('response received', statusCode) + console.log('headers', headers) + // For a DELETE request we expect a 204 response with no body if successful, in which case getting the body content with .text() or .json() will fail + if (statusCode !== 204) { + console.log('delete successful') + } else { + const data = await body.text() + console.log('received unexpected data', data) + } +} +``` diff --git a/examples/request.js b/examples/request.js index 1b032544d5f..34bf91cebd6 100644 --- a/examples/request.js +++ b/examples/request.js @@ -2,12 +2,13 @@ const { request } = require('../') -async function main () { +async function getRequest (port = 3001) { + // A simple GET request const { statusCode, headers, body - } = await request('http://localhost:3001/') + } = await request(`http://localhost:${port}/`) const data = await body.text() console.log('response received', statusCode) @@ -15,4 +16,77 @@ async function main () { console.log('data', data) } -main() +async function postJSONRequest (port = 3001) { + // Make a JSON POST request: + + const requestBody = { + hello: 'JSON POST Example body' + } + + const { + statusCode, + headers, + body + } = await request( + `http://localhost:${port}/json`, + { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(requestBody) } + ) + + // .json() will fail if we did not receive a valid json body in response: + const decodedJson = await body.json() + console.log('response received', statusCode) + console.log('headers', headers) + console.log('data', decodedJson) +} + +async function postFormRequest (port = 3001) { + // Make a URL-encoded form POST request: + const qs = require('querystring') + + const requestBody = { + hello: 'URL Encoded Example body' + } + + const { + statusCode, + headers, + body + } = await request( + `http://localhost:${port}/form`, + { method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: qs.stringify(requestBody) } + ) + + const data = await body.text() + console.log('response received', statusCode) + console.log('headers', headers) + console.log('data', data) +} + +async function deleteRequest (port = 3001) { + // Make a DELETE request + const { + statusCode, + headers, + body + } = await request( + `http://localhost:${port}/something`, + { method: 'DELETE' } + ) + + console.log('response received', statusCode) + console.log('headers', headers) + // For a DELETE request we expect a 204 response with no body if successful, in which case getting the body content with .text() or .json() will fail + if (statusCode !== 204) { + console.log('delete successful') + } else { + const data = await body.text() + console.log('received unexpected data', data) + } +} + +module.exports = { + getRequest, + postJSONRequest, + postFormRequest, + deleteRequest +} diff --git a/test/examples.js b/test/examples.js new file mode 100644 index 00000000000..6ff17a0d784 --- /dev/null +++ b/test/examples.js @@ -0,0 +1,46 @@ +'use strict' + +const { createServer } = require('http') +const { test } = require('tap') +const examples = require('../examples/request.js') + +test('request examples', async (t) => { + let lastReq + const exampleServer = createServer((req, res) => { + lastReq = req + if (req.method === 'DELETE') { + res.statusCode = 204 + return res.end() + } else if (req.method === 'POST') { + res.statusCode = 200 + if (req.url === '/json') { + res.end('{"hello":"JSON Response"}') + } else { + res.end('hello=form') + } + } else { + res.statusCode = 200 + res.end('hello') + } + }) + + t.teardown(exampleServer.close.bind(exampleServer)) + + await exampleServer.listen(0) + + await examples.getRequest(exampleServer.address().port) + t.equal(lastReq.method, 'GET') + + await examples.postJSONRequest(exampleServer.address().port) + t.equal(lastReq.method, 'POST') + t.equal(lastReq.headers['content-type'], 'application/json') + + await examples.postFormRequest(exampleServer.address().port) + t.equal(lastReq.method, 'POST') + t.equal(lastReq.headers['content-type'], 'application/x-www-form-urlencoded') + + await examples.deleteRequest(exampleServer.address().port) + t.equal(lastReq.method, 'DELETE') + + t.end() +}) From eebfc65f01aa5c4d31eef813cd25480c3896b648 Mon Sep 17 00:00:00 2001 From: James Crosby Date: Thu, 26 Oct 2023 12:15:55 +0100 Subject: [PATCH 2/3] fix DELETE example --- examples/README.md | 6 ++++-- examples/request.js | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/README.md b/examples/README.md index c8051344559..60965c2898a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -87,9 +87,11 @@ async function deleteRequest (port = 3001) { console.log('response received', statusCode) console.log('headers', headers) - // For a DELETE request we expect a 204 response with no body if successful, in which case getting the body content with .text() or .json() will fail - if (statusCode !== 204) { + // For a DELETE request we expect a 204 response with no body if successful, in which case getting the body content with .json() will fail + if (statusCode === 204) { console.log('delete successful') + // always consume the body if there is one: + await body.dump() } else { const data = await body.text() console.log('received unexpected data', data) diff --git a/examples/request.js b/examples/request.js index 34bf91cebd6..01dcf58b03b 100644 --- a/examples/request.js +++ b/examples/request.js @@ -75,9 +75,11 @@ async function deleteRequest (port = 3001) { console.log('response received', statusCode) console.log('headers', headers) - // For a DELETE request we expect a 204 response with no body if successful, in which case getting the body content with .text() or .json() will fail - if (statusCode !== 204) { + // For a DELETE request we expect a 204 response with no body if successful, in which case getting the body content with .json() will fail + if (statusCode === 204) { console.log('delete successful') + // always consume the body if there is one: + await body.dump() } else { const data = await body.text() console.log('received unexpected data', data) From 1926d82e3343ed64f2a7b4f8f8e42d0bf35aa735 Mon Sep 17 00:00:00 2001 From: James Crosby Date: Fri, 27 Oct 2023 11:51:48 +0100 Subject: [PATCH 3/3] ensure test covers error handling part of example --- test/examples.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/examples.js b/test/examples.js index 6ff17a0d784..9b814820cb8 100644 --- a/test/examples.js +++ b/test/examples.js @@ -14,6 +14,7 @@ test('request examples', async (t) => { } else if (req.method === 'POST') { res.statusCode = 200 if (req.url === '/json') { + res.setHeader('content-type', 'application/json') res.end('{"hello":"JSON Response"}') } else { res.end('hello=form') @@ -24,9 +25,18 @@ test('request examples', async (t) => { } }) + const errorServer = createServer((req, res) => { + lastReq = req + res.statusCode = 400 + res.setHeader('content-type', 'application/json') + res.end('{"error":"an error"}') + }) + t.teardown(exampleServer.close.bind(exampleServer)) + t.teardown(errorServer.close.bind(errorServer)) await exampleServer.listen(0) + await errorServer.listen(0) await examples.getRequest(exampleServer.address().port) t.equal(lastReq.method, 'GET') @@ -42,5 +52,8 @@ test('request examples', async (t) => { await examples.deleteRequest(exampleServer.address().port) t.equal(lastReq.method, 'DELETE') + await examples.deleteRequest(errorServer.address().port) + t.equal(lastReq.method, 'DELETE') + t.end() })