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": {
|
||||
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
|
||||
"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": {
|
||||
"@astrojs/webapi": "^0.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"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);
|
||||
return {
|
||||
async handler(req: IncomingMessage, res: ServerResponse, next?: (err?: unknown) => void) {
|
||||
const route = app.match(req);
|
||||
try {
|
||||
const route = app.match(req);
|
||||
|
||||
if (route) {
|
||||
try {
|
||||
const response = await app.render(req);
|
||||
await writeWebResponse(res, response);
|
||||
} catch (err: unknown) {
|
||||
if (next) {
|
||||
next(err);
|
||||
} else {
|
||||
throw err;
|
||||
if (route) {
|
||||
try {
|
||||
const response = await app.render(req);
|
||||
await writeWebResponse(res, response);
|
||||
} catch (err: unknown) {
|
||||
if (next) {
|
||||
next(err);
|
||||
} else {
|
||||
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