summaryrefslogtreecommitdiff
path: root/packages/astro/src/runtime/server/endpoint.ts
blob: 89c35957c112c142342cf10645d53715e6e6e4c4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import type { APIContext, EndpointHandler, Params } from '../../@types/astro';
import { type LogOptions, warn } from '../../core/logger/core.js';

function getHandlerFromModule(mod: EndpointHandler, method: string, logging: LogOptions) {
	const lowerCaseMethod = method.toLowerCase();

	// TODO: remove in Astro 4.0
	if (mod[lowerCaseMethod]) {
		warn(
			logging,
			'astro',
			`Lower case endpoint names are deprecated and will not be supported in Astro 4.0. Rename the endpoint ${lowerCaseMethod} to ${method}.`
		);
	}
	// If there was an exact match on `method`, return that function.
	if (mod[method]) {
		return mod[method];
	}

	// TODO: remove in Astro 4.0
	if (mod[lowerCaseMethod]) {
		return mod[lowerCaseMethod];
	}
	// TODO: remove in Astro 4.0
	// Handle `del` instead of `delete`, since `delete` is a reserved word in JS.
	if (method === 'delete' && mod['del']) {
		return mod['del'];
	}
	// TODO: remove in Astro 4.0
	// If a single `all` handler was used, return that function.
	if (mod['all']) {
		return mod['all'];
	}
	if (mod['ALL']) {
		return mod['ALL'];
	}
	// Otherwise, no handler found.
	return undefined;
}

/** Renders an endpoint request to completion, returning the body. */
export async function renderEndpoint(
	mod: EndpointHandler,
	context: APIContext,
	ssr: boolean,
	logging: LogOptions
) {
	const { request } = context;

	const chosenMethod = request.method?.toUpperCase();
	const handler = getHandlerFromModule(mod, chosenMethod, logging);
	// TODO: remove the 'get' check in Astro 4.0
	if (!ssr && ssr === false && chosenMethod && chosenMethod !== 'GET' && chosenMethod !== 'get') {
		// eslint-disable-next-line no-console
		console.warn(`
${chosenMethod} requests are not available when building a static site. Update your config to \`output: 'server'\` or \`output: 'hybrid'\` with an \`export const prerender = false\` to handle ${chosenMethod} requests.`);
	}
	if (!handler || typeof handler !== 'function') {
		// No handler found, so this should be a 404. Using a custom header
		// to signal to the renderer that this is an internal 404 that should
		// be handled by a custom 404 route if possible.
		let response = new Response(null, {
			status: 404,
			headers: {
				'X-Astro-Response': 'Not-Found',
			},
		});
		return response;
	}

	const proxy = new Proxy(context, {
		get(target, prop) {
			if (prop in target) {
				return Reflect.get(target, prop);
			} else {
				return undefined;
			}
		},
	}) as APIContext & Params;

	return handler.call(mod, proxy, request);
}