Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Content-length on httpApiCall #250

Merged
merged 10 commits into from
Apr 26, 2024
12 changes: 7 additions & 5 deletions lib/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ const intToIp = (int) => {

const httpApiCall = async (url, { method = 'POST', headers = {}, body }) => {
const mimeType = 'application/json';
const custom = { 'Content-Type': mimeType, ...headers };
if (body) headers['Content-Length'] = Buffer.byteLength(body);
const options = { method, headers: custom, body };
return await fetch(url, options).then(async (res) => {
const options = {
method,
body,
headers: { ...headers, 'Content-Type': mimeType },
};
return await fetch(url, options).then((res) => {
tshemsedinov marked this conversation as resolved.
Show resolved Hide resolved
const code = res.status;
if (code === 200) return await res.json();
if (code === 200) return res.json();
const dest = `for ${method} ${url}`;
throw new Error(`HTTP status code ${code} ${dest}`);
});
Expand Down
104 changes: 103 additions & 1 deletion test/network.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

const http = require('node:http');
const { once } = require('node:events');
const metatests = require('metatests');
const metautil = require('..');

Expand Down Expand Up @@ -73,7 +75,7 @@ metatests.case(
},
);

metatests.test('Newtork: httpApiCall', async (test) => {
metatests.test('Network: httpApiCall', async (test) => {
const res1 = await metautil.httpApiCall(RATES_API_URL, { method: 'GET' });
test.strictSame(typeof res1.disclaimer, 'string');
test.strictSame(typeof res1.license, 'string');
Expand All @@ -96,3 +98,103 @@ metatests.test('Newtork: httpApiCall', async (test) => {

test.end();
});

metatests.test('Network: httpApiCall (POST)', async (test) => {
const expectedBody = '{"key": "value"}';
tshemsedinov marked this conversation as resolved.
Show resolved Hide resolved
const expectedLength = Buffer.byteLength(expectedBody).toString();

const server = http.createServer();

server.on('request', async (req, res) => {
let body = '';
for await (const chunk of req) body += chunk;

test.strictSame(body, expectedBody);
test.strictSame(req.headers['content-length'], expectedLength);
test.strictSame(req.headers['content-type'], 'application/json');
test.strictSame(req.headers['custom-header'], 'custom-value');
test.strictSame(req.method, 'POST');

res.end('{"key": "value"}');
tshemsedinov marked this conversation as resolved.
Show resolved Hide resolved
});

server.listen(0);

await once(server, 'listening');

const url = `http://localhost:${server.address().port}`;
const headers = { 'Custom-Header': 'custom-value' };
const body = '{"key": "value"}';
const method = 'POST';

try {
const res = await metautil.httpApiCall(url, { method, headers, body });
test.strictSame(res, { key: 'value' });
} catch (err) {
test.error(err);
}

server.close();
});

metatests.test('Network: httpApiCall (POST without body)', async (test) => {
const server = http.createServer();

server.on('request', async (req, res) => {
let body = '';
for await (const chunk of req) body += chunk;

test.strictSame(req.headers['content-length'], '0');
test.strictSame(req.headers['content-type'], 'application/json');
test.strictSame(req.headers['custom-header'], 'custom-value');
test.strictSame(req.method, 'POST');
test.strictSame(body, '');

res.end('{"key": "value"}');
tshemsedinov marked this conversation as resolved.
Show resolved Hide resolved
});

server.listen(0);

await once(server, 'listening');

const url = `http://localhost:${server.address().port}`;
const headers = { 'Custom-Header': 'custom-value' };

try {
const res = await metautil.httpApiCall(url, { method: 'POST', headers });
test.strictSame(res, { key: 'value' });
} catch (err) {
test.error(err);
}

server.close();
});

metatests.test('Network: httpApiCall (GET)', async (test) => {
const server = http.createServer();

server.on('request', async (req, res) => {
test.strictSame(req.headers['content-length'], undefined);
test.strictSame(req.headers['content-type'], 'application/json');
test.strictSame(req.headers['custom-header'], 'custom-value');
test.strictSame(req.method, 'GET');

res.end('{"key": "value"}');
tshemsedinov marked this conversation as resolved.
Show resolved Hide resolved
});

server.listen(0);

await once(server, 'listening');

const url = `http://localhost:${server.address().port}`;
const headers = { 'Custom-Header': 'custom-value' };

try {
const res = await metautil.httpApiCall(url, { method: 'GET', headers });
test.strictSame(res, { key: 'value' });
} catch (err) {
test.error(err);
}

server.close();
});