mirror of
https://github.com/withastro/astro.git
synced 2025-03-10 23:01:26 -05:00
Fixes Node adapter receiving a request body (#4023)
* Fixes Node adapter receiving a request body * Updated lockfile
This commit is contained in:
parent
9970dde630
commit
3b104fb8a5
6 changed files with 134 additions and 14 deletions
|
@ -24,13 +24,15 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
|
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
|
||||||
"build:ci": "astro-scripts build \"src/**/*.ts\"",
|
"build:ci": "astro-scripts build \"src/**/*.ts\"",
|
||||||
"dev": "astro-scripts dev \"src/**/*.ts\""
|
"dev": "astro-scripts dev \"src/**/*.ts\"",
|
||||||
|
"test": "mocha --exit --timeout 20000 test/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/webapi": "^0.12.0"
|
"@astrojs/webapi": "^0.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"astro": "workspace:*",
|
"astro": "workspace:*",
|
||||||
"astro-scripts": "workspace:*"
|
"astro-scripts": "workspace:*",
|
||||||
|
"node-mocks-http": "^1.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,21 +12,28 @@ export function createExports(manifest: SSRManifest) {
|
||||||
const app = new NodeApp(manifest);
|
const app = new NodeApp(manifest);
|
||||||
return {
|
return {
|
||||||
async handler(req: IncomingMessage, res: ServerResponse, next?: (err?: unknown) => void) {
|
async handler(req: IncomingMessage, res: ServerResponse, next?: (err?: unknown) => void) {
|
||||||
const route = app.match(req);
|
try {
|
||||||
|
const route = app.match(req);
|
||||||
|
|
||||||
if (route) {
|
if (route) {
|
||||||
try {
|
try {
|
||||||
const response = await app.render(req);
|
const response = await app.render(req);
|
||||||
await writeWebResponse(res, response);
|
await writeWebResponse(res, response);
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if (next) {
|
if (next) {
|
||||||
next(err);
|
next(err);
|
||||||
} else {
|
} else {
|
||||||
throw err;
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (next) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
} catch(err: unknown) {
|
||||||
|
if(!res.headersSent) {
|
||||||
|
res.writeHead(500, `Server error`);
|
||||||
|
res.end();
|
||||||
}
|
}
|
||||||
} else if (next) {
|
|
||||||
return next();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
37
packages/integrations/node/test/api-route.test.js
Normal file
37
packages/integrations/node/test/api-route.test.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import nodejs from '../dist/index.js';
|
||||||
|
import { loadFixture, createRequestAndResponse, toPromise } from './test-utils.js';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
|
||||||
|
|
||||||
|
describe('API routes', () => {
|
||||||
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
fixture = await loadFixture({
|
||||||
|
root: './fixtures/api-route/',
|
||||||
|
experimental: {
|
||||||
|
ssr: true,
|
||||||
|
},
|
||||||
|
adapter: nodejs(),
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can get the request body', async () => {
|
||||||
|
const { handler } = await import('./fixtures/api-route/dist/server/entry.mjs');
|
||||||
|
|
||||||
|
let { req, res, done } = createRequestAndResponse({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/recipes'
|
||||||
|
});
|
||||||
|
|
||||||
|
handler(req, res);
|
||||||
|
req.send(JSON.stringify({ id: 2 }));
|
||||||
|
|
||||||
|
let [ buffer ] = await done;
|
||||||
|
let json = JSON.parse(buffer.toString('utf-8'));
|
||||||
|
expect(json.length).to.equal(1);
|
||||||
|
expect(json[0].name).to.equal('Broccoli Soup');
|
||||||
|
});
|
||||||
|
});
|
9
packages/integrations/node/test/fixtures/api-route/package.json
vendored
Normal file
9
packages/integrations/node/test/fixtures/api-route/package.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"name": "@test/nodejs-api-route",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"astro": "workspace:*",
|
||||||
|
"@astrojs/node": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
24
packages/integrations/node/test/fixtures/api-route/src/pages/recipes.js
vendored
Normal file
24
packages/integrations/node/test/fixtures/api-route/src/pages/recipes.js
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
export async function post({ request }) {
|
||||||
|
let body = await request.json();
|
||||||
|
const recipes = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Potato Soup'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Broccoli Soup'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let out = recipes.filter(r => {
|
||||||
|
return r.id === body.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(JSON.stringify(out), {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
41
packages/integrations/node/test/test-utils.js
Normal file
41
packages/integrations/node/test/test-utils.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { loadFixture as baseLoadFixture } from '../../../astro/test/test-utils.js';
|
||||||
|
import httpMocks from 'node-mocks-http';
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../../../astro/test/test-utils').Fixture} Fixture
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function loadFixture(inlineConfig) {
|
||||||
|
if (!inlineConfig || !inlineConfig.root)
|
||||||
|
throw new Error("Must provide { root: './fixtures/...' }");
|
||||||
|
|
||||||
|
// resolve the relative root (i.e. "./fixtures/tailwindcss") to a full filepath
|
||||||
|
// without this, the main `loadFixture` helper will resolve relative to `packages/astro/test`
|
||||||
|
return baseLoadFixture({
|
||||||
|
...inlineConfig,
|
||||||
|
root: new URL(inlineConfig.root, import.meta.url).toString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRequestAndResponse(reqOptions) {
|
||||||
|
let req = httpMocks.createRequest(reqOptions);
|
||||||
|
|
||||||
|
let res = httpMocks.createResponse({
|
||||||
|
eventEmitter: EventEmitter,
|
||||||
|
req
|
||||||
|
});
|
||||||
|
|
||||||
|
let done = toPromise(res);
|
||||||
|
|
||||||
|
return { req, res, done };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toPromise(res) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
res.on('end', () => {
|
||||||
|
let chunks = res._getChunks();
|
||||||
|
resolve(chunks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue