mirror of
https://github.com/withastro/astro.git
synced 2025-01-06 22:10:10 -05:00
qol(endpoints): helpful error message when a response is not provided (#10455)
* qol(endpoints): helpful error message when a response is not provded * add changeset * add test
This commit is contained in:
parent
7138aa4678
commit
c12666166d
4 changed files with 84 additions and 0 deletions
5
.changeset/cuddly-suits-hunt.md
Normal file
5
.changeset/cuddly-suits-hunt.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"astro": patch
|
||||
---
|
||||
|
||||
Adds a helpful error message that will be shown when an endpoint does not return a `Response`.
|
|
@ -788,6 +788,29 @@ export const MiddlewareNotAResponse = {
|
|||
message: 'Any data returned from middleware must be a valid `Response` object.',
|
||||
} satisfies ErrorData;
|
||||
|
||||
/**
|
||||
* @docs
|
||||
* @description
|
||||
* Thrown when an endpoint does not return anything or returns an object that is not a `Response` object.
|
||||
*
|
||||
* An endpoint must return either a `Response`, or a `Promise` that resolves with a `Response`. For example:
|
||||
* ```ts
|
||||
* import type { APIContext } from 'astro';
|
||||
*
|
||||
* export async function GET({ request, url, cookies }: APIContext): Promise<Response> {
|
||||
* return Response.json({
|
||||
* success: true,
|
||||
* result: 'Data from Astro Endpoint!'
|
||||
* })
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const EndpointDidNotReturnAResponse = {
|
||||
name: 'EndpointDidNotReturnAResponse',
|
||||
title: 'The endpoint did not return a `Response`.',
|
||||
message: 'An endpoint must return either a `Response`, or a `Promise` that resolves with a `Response`.',
|
||||
} satisfies ErrorData;
|
||||
|
||||
/**
|
||||
* @docs
|
||||
* @description
|
||||
|
|
|
@ -2,6 +2,8 @@ import { bold } from 'kleur/colors';
|
|||
import type { APIContext, EndpointHandler } from '../../@types/astro.js';
|
||||
import { REROUTABLE_STATUS_CODES, REROUTE_DIRECTIVE_HEADER } from '../../core/constants.js';
|
||||
import type { Logger } from '../../core/logger/core.js';
|
||||
import { AstroError } from '../../core/errors/errors.js';
|
||||
import { EndpointDidNotReturnAResponse } from '../../core/errors/errors-data.js';
|
||||
|
||||
/** Renders an endpoint request to completion, returning the body. */
|
||||
export async function renderEndpoint(
|
||||
|
@ -49,6 +51,11 @@ export async function renderEndpoint(
|
|||
}
|
||||
|
||||
const response = await handler.call(mod, context);
|
||||
|
||||
if (!response || response instanceof Response === false) {
|
||||
throw new AstroError(EndpointDidNotReturnAResponse)
|
||||
}
|
||||
|
||||
// Endpoints explicitly returning 404 or 500 response status should
|
||||
// NOT be subject to rerouting to 404.astro or 500.astro.
|
||||
if (REROUTABLE_STATUS_CODES.includes(response.status)) {
|
||||
|
|
49
packages/astro/test/units/runtime/endpoints.test.js
Normal file
49
packages/astro/test/units/runtime/endpoints.test.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
import * as assert from 'node:assert/strict';
|
||||
import { after, before, describe, it } from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createContainer } from '../../../dist/core/dev/container.js';
|
||||
import testAdapter from '../../test-adapter.js';
|
||||
import {
|
||||
createBasicSettings,
|
||||
createFs,
|
||||
createRequestAndResponse,
|
||||
defaultLogger,
|
||||
} from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/api-routes/', import.meta.url);
|
||||
const fileSystem = {
|
||||
'/src/pages/incorrect.ts': `export const GET = _ => {}`,
|
||||
};
|
||||
|
||||
describe('endpoints', () => {
|
||||
let container;
|
||||
let settings;
|
||||
|
||||
before(async () => {
|
||||
const fs = createFs(fileSystem, root);
|
||||
settings = await createBasicSettings({
|
||||
root: fileURLToPath(root),
|
||||
output: 'server',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
container = await createContainer({
|
||||
fs,
|
||||
settings,
|
||||
logger: defaultLogger,
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await container.close();
|
||||
});
|
||||
|
||||
it('should respond with 500 for incorrect implementation', async () => {
|
||||
const { req, res, done } = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
url: '/incorrect',
|
||||
});
|
||||
container.handle(req, res);
|
||||
await done;
|
||||
assert.equal(res.statusCode, 500);
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue