Skip to content

Commit

Permalink
qol(endpoints): helpful error message when a response is not provided (
Browse files Browse the repository at this point in the history
…#10455)

* qol(endpoints): helpful error message when a response is not provded

* add changeset

* add test
  • Loading branch information
lilnasy committed Mar 18, 2024
1 parent 7138aa4 commit c126661
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/cuddly-suits-hunt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro": patch
---

Adds a helpful error message that will be shown when an endpoint does not return a `Response`.
23 changes: 23 additions & 0 deletions packages/astro/src/core/errors/errors-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions packages/astro/src/runtime/server/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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)) {
Expand Down
49 changes: 49 additions & 0 deletions packages/astro/test/units/runtime/endpoints.test.js
Original file line number Diff line number Diff line change
@@ -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);
});
});

0 comments on commit c126661

Please sign in to comment.