feat: upper case the name of the endpoints (#7783)

Co-authored-by: Bjorn Lu <bjornlu.dev@gmail.com>
Co-authored-by: Yan Thomas <61414485+Yan-Thomas@users.noreply.github.com>
Co-authored-by: Chris Swithinbank <swithinbank@gmail.com>
This commit is contained in:
Emanuele Stoppa 2023-07-26 08:53:31 +01:00
parent e9f697cf14
commit a6e5135765
45 changed files with 116 additions and 53 deletions

View file

@ -0,0 +1,35 @@
---
'astro': major
---
Lowercase names for endpoint functions are now deprecated.
Rename functions to their uppercase equivalent:
```diff
- export function get() {
+ export function GET() {
return new Response(JSON.stringify({ "title": "Bob's blog" }));
}
- export function post() {
+ export function POST() {
return new Response(JSON.stringify({ "title": "Bob's blog" }));
}
- export function put() {
+ export function PUT() {
return new Response(JSON.stringify({ "title": "Bob's blog" }));
}
- export function all() {
+ export function ALL() {
return new Response(JSON.stringify({ "title": "Bob's blog" }));
}
// you can use the whole word "DELETE"
- export function del() {
+ export function DELETE() {
return new Response(JSON.stringify({ "title": "Bob's blog" }));
}
```

View file

@ -24,7 +24,7 @@ async function loadRemoteImage(src: URL) {
/**
* Endpoint used in dev and SSR to serve optimized images by the base image services
*/
export const get: APIRoute = async ({ request }) => {
export const GET: APIRoute = async ({ request }) => {
try {
const imageService = await getConfiguredImageService();

View file

@ -7,13 +7,13 @@ import type {
Params,
} from '../../@types/astro';
import type { Environment, RenderContext } from '../render/index';
import { renderEndpoint } from '../../runtime/server/index.js';
import { ASTRO_VERSION } from '../constants.js';
import { AstroCookies, attachToResponse } from '../cookies/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
import { warn } from '../logger/core.js';
import { callMiddleware } from '../middleware/callMiddleware.js';
const clientAddressSymbol = Symbol.for('astro.clientAddress');
const clientLocalsSymbol = Symbol.for('astro.locals');
@ -119,11 +119,11 @@ export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>
onRequest as MiddlewareEndpointHandler,
context,
async () => {
return await renderEndpoint(mod, context, env.ssr);
return await renderEndpoint(mod, context, env.ssr, env.logging);
}
);
} else {
response = await renderEndpoint(mod, context, env.ssr);
response = await renderEndpoint(mod, context, env.ssr, env.logging);
}
if (response instanceof Response) {

View file

@ -1,28 +1,56 @@
import type { APIContext, EndpointHandler, Params } from '../../@types/astro';
import { type LogOptions, warn } from '../../core/logger/core.js';
function getHandlerFromModule(mod: EndpointHandler, method: string) {
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) {
export async function renderEndpoint(
mod: EndpointHandler,
context: APIContext,
ssr: boolean,
logging: LogOptions
) {
const { request, params } = context;
const chosenMethod = request.method?.toLowerCase();
const handler = getHandlerFromModule(mod, chosenMethod);
if (!ssr && ssr === false && chosenMethod && chosenMethod !== 'get') {
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.`);

View file

@ -1,5 +1,5 @@
import type { APIRoute } from 'astro';
export const get: APIRoute = async function () {
export const GET: APIRoute = async function () {
return new Response(new Uint8Array([0xff]));
};

View file

@ -14,7 +14,7 @@ export function getStaticPaths() {
]
}
export function get({ params, request }) {
export function GET({ params, request }) {
return {
body: JSON.stringify({
param: params.param,

View file

@ -1,5 +1,5 @@
export function post({ cookies }) {
export function POST({ cookies }) {
const mode = cookies.get('prefs').json().mode;
cookies.set('prefs', {

View file

@ -5,7 +5,7 @@ export async function getStaticPaths() {
];
}
export async function get() {
export async function GET() {
return {
body: JSON.stringify({
title: '[slug]'

View file

@ -1,4 +1,4 @@
export async function get() {
export async function GET() {
const docs = await import.meta.glob('./*.md', { eager: true });
return {
body: JSON.stringify(Object.values(docs).map(doc => doc.frontmatter)),

View file

@ -1,6 +1,6 @@
import { getHeadings } from './with-layout.md';
export async function get() {
export async function GET() {
return {
body: JSON.stringify({
headings: getHeadings(),

View file

@ -1,6 +1,6 @@
import { rawContent, compiledContent } from './basic.md';
export async function get() {
export async function GET() {
return {
body: JSON.stringify({
raw: rawContent(),

View file

@ -1,6 +1,6 @@
import { frontmatter } from './vite-env-vars.md';
export async function get() {
export async function GET() {
return {
body: JSON.stringify(frontmatter),
}

View file

@ -1,6 +1,6 @@
import { getEntry, getEntries } from 'astro:content';
export async function get() {
export async function GET() {
const welcomePost = await getEntry('blog', 'welcome');
if (!welcomePost?.data) {

View file

@ -2,7 +2,7 @@ import { getCollection } from 'astro:content';
import * as devalue from 'devalue';
import { stripAllRenderFn } from '../utils.js';
export async function get() {
export async function GET() {
const withoutConfig = stripAllRenderFn(await getCollection('without-config'));
const withSchemaConfig = stripAllRenderFn(await getCollection('with-schema-config'));
const withSlugConfig = stripAllRenderFn(await getCollection('with-custom-slugs'));

View file

@ -2,7 +2,7 @@ import { getEntryBySlug } from 'astro:content';
import * as devalue from 'devalue';
import { stripRenderFn } from '../utils.js';
export async function get() {
export async function GET() {
const columbiaWithoutConfig = stripRenderFn(await getEntryBySlug('without-config', 'columbia'));
const oneWithSchemaConfig = stripRenderFn(await getEntryBySlug('with-schema-config', 'one'));
const twoWithSlugConfig = stripRenderFn(await getEntryBySlug('with-custom-slugs', 'interesting-two'));

View file

@ -1,6 +1,6 @@
import type { APIRoute } from "../../../../../src/@types/astro";
export const get = (async ({ params, request }) => {
export const GET = (async ({ params, request }) => {
const url = new URL(request.url);
const src = url.searchParams.get("src");

View file

@ -7,7 +7,7 @@ export function getStaticPaths() {
}
/** @param {import('astro').APIContext} params */
export async function get({ params }) {
export async function GET({ params }) {
const { id } = params;
const author = await getEntry('authors-without-config', id);
if (!author) {

View file

@ -1,6 +1,6 @@
import { getCollection } from 'astro:content';
export async function get() {
export async function GET() {
const authors = await getCollection('authors-without-config');
return {

View file

@ -7,7 +7,7 @@ export function getStaticPaths() {
}
/** @param {import('astro').APIContext} params */
export async function get({ params }) {
export async function GET({ params }) {
const { lang } = params;
const translations = await getEntry('i18n', lang);
if (!translations) {

View file

@ -1,6 +1,6 @@
import { getCollection } from 'astro:content';
export async function get() {
export async function GET() {
const translations = await getCollection('i18n');
return {

View file

@ -2,7 +2,7 @@ import type { APIRoute } from "astro";
const slugs = ["one", undefined];
export const get: APIRoute = ({ params }) => {
export const GET: APIRoute = ({ params }) => {
return {
body: JSON.stringify({
slug: params.slug || "index",

View file

@ -1,4 +1,4 @@
export function get() {
export function GET() {
const object = {
name: 'Endpoint!!',
};

View file

@ -1,7 +1,7 @@
// Returns the file body for this non-HTML file.
// The content type is based off of the extension in the filename,
// in this case: about.json.
export async function get() {
export async function GET() {
return {
body: JSON.stringify({
name: 'Astro',

View file

@ -2,7 +2,7 @@ import { promises as fs } from 'node:fs';
import type { APIRoute } from 'astro';
export const get: APIRoute = async function get() {
export const GET: APIRoute = async function get() {
try {
// Image is in the public domain. Sourced from
// https://en.wikipedia.org/wiki/File:Portrait_placeholder.png

View file

@ -1,6 +1,6 @@
import type { APIRoute } from 'astro';
export const get: APIRoute = async ({ params }) => {
export const GET: APIRoute = async ({ params }) => {
return {
body: JSON.stringify({
path: params.slug,

View file

@ -1,6 +1,6 @@
import type { APIRoute } from 'astro';
export const get: APIRoute = async ({ params }) => {
export const GET: APIRoute = async ({ params }) => {
return {
body: JSON.stringify({
foo: params.foo,

View file

@ -1,5 +1,5 @@
export function post() {
export function POST() {
return {
body: JSON.stringify({ ok: true })
};

View file

@ -1,6 +1,6 @@
import fs from 'node:fs';
export function get() {
export function GET() {
return {
body: 'ok'
};

View file

@ -1,7 +1,7 @@
/**
* @param {import('astro').APIContext} api
*/
export function get(ctx) {
export function GET(ctx) {
return {
body: JSON.stringify({
cookiesExist: !!ctx.cookies,

View file

@ -1,5 +1,5 @@
export function get() {
export function GET() {
return {
body: JSON.stringify([
{ name: 'lettuce' },
@ -9,7 +9,7 @@ export function get() {
};
}
export async function post({ params, request }) {
export async function POST({ params, request }) {
const body = await request.text();
return new Response(body === `some data` ? `ok` : `not ok`, {
status: 200,

View file

@ -1,5 +1,5 @@
/** @type {import('astro').APIRoute} */
export function post({ cookies }) {
export function POST({ cookies }) {
cookies.set('foo', 'foo', {
httpOnly: true
});

View file

@ -1,5 +1,5 @@
export function get({ params }) {
export function GET({ params }) {
return {
body: JSON.stringify(params)
};

View file

@ -1,5 +1,5 @@
export async function get({ locals }) {
export async function GET({ locals }) {
let out = { ...locals };
return new Response(JSON.stringify(out), {

View file

@ -7,7 +7,7 @@ export async function getStaticPaths() {
];
}
export async function get() {
export async function GET() {
return {
body: JSON.stringify({
title: '[slug]'

View file

@ -1,4 +1,4 @@
export async function get() {
export async function GET() {
return {
body: JSON.stringify({
name: 'Astro Technology Company',

View file

@ -5,7 +5,7 @@ export async function getStaticPaths() {
]
}
export async function get({ params }) {
export async function GET({ params }) {
return {
body: JSON.stringify({
slug: params.slug,

View file

@ -13,7 +13,7 @@ async function fetchPosts() {
return posts.sort((a, b) => a.title.localeCompare(b.title));
}
export async function get() {
export async function GET() {
const posts = await fetchPosts();
return {

View file

@ -5,7 +5,7 @@ export async function getStaticPaths() {
];
}
export async function get({ params }) {
export async function GET({ params }) {
return {
body: JSON.stringify({
slug: params.slug,

View file

@ -5,7 +5,7 @@ export async function getStaticPaths() {
];
}
export async function get({ params }) {
export async function GET({ params }) {
return {
body: JSON.stringify({
slug: params.slug,

View file

@ -1,4 +1,4 @@
export async function get() {
export async function GET() {
return {
body: JSON.stringify({
title: 'home'

View file

@ -5,7 +5,7 @@ export async function getStaticPaths() {
];
}
export async function get({ params }) {
export async function GET({ params }) {
return {
body: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 200">
<title>${params.image}</title>

View file

@ -1,6 +1,6 @@
import { readFileSync } from "node:fs";
export async function get({ params, request }) {
export async function GET({ params, request }) {
const buffer = readFileSync(new URL('../../astro.png', import.meta.url));
return {
body: buffer.toString('hex'),

View file

@ -1,4 +1,4 @@
export async function get() {
export async function GET() {
return {
body: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 200">
<title>Static SVG</title>

View file

@ -20,7 +20,7 @@ async function loadRemoteImage(src: URL) {
}
}
export const get: APIRoute = async ({ request }) => {
export const GET: APIRoute = async ({ request }) => {
try {
const url = new URL(request.url);
const transform = loader.parseTransform(url.searchParams);

View file

@ -1,4 +1,4 @@
import { Tokenizer } from '@markdoc/markdoc';
import type { Tokenizer } from '@markdoc/markdoc';
import { Parser } from 'htmlparser2';
import type * as Token from 'markdown-it/lib/token';