Conform to API route signature (#3272)

* Conform to API route signature

* Rename to API route

* Update ssr test

* Update packages/astro/test/fixtures/ssr-dynamic/src/pages/api/products/[id].js

Co-authored-by: Ben Holmes <hey@bholmes.dev>

* Adds a changeset

* Make PR review changes

Co-authored-by: Ben Holmes <hey@bholmes.dev>
This commit is contained in:
Matthew Phillips 2022-05-04 14:55:37 -04:00 committed by GitHub
parent d825d376f8
commit 6643a3931d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 179 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Implements the Dynamic Route API RFC

View file

@ -856,12 +856,27 @@ export interface AstroAdapter {
args?: any;
}
export interface APIContext {
params: Params;
request: Request;
}
export interface EndpointOutput<Output extends Body = Body> {
body: Output;
}
interface APIRoute {
(context: APIContext): EndpointOutput | Response;
/**
* @deprecated
* Use { context: APIRouteContext } object instead.
*/
(params: Params, request: Request): EndpointOutput | Response;
}
export interface EndpointHandler {
[method: string]: (params: any, request: Request) => EndpointOutput | Response;
[method: string]: APIRoute;
}
export interface AstroRenderer {

View file

@ -52,6 +52,7 @@ export async function callGetStaticPaths({
const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed;
keyedStaticPaths.keyed = new Map<string, GetStaticPathsItem>();
for (const sp of keyedStaticPaths) {
const paramsKey = stringifyParams(sp.params);
keyedStaticPaths.keyed.set(paramsKey, sp);

View file

@ -1,4 +1,5 @@
import type {
APIContext,
AstroComponentMetadata,
AstroGlobalPartial,
EndpointHandler,
@ -468,7 +469,46 @@ export async function renderEndpoint(mod: EndpointHandler, request: Request, par
`Endpoint handler not found! Expected an exported function for "${chosenMethod}"`
);
}
return await handler.call(mod, params, request);
if(handler.length > 1) {
// eslint-disable-next-line no-console
console.warn(`
API routes with 2 arguments have been deprecated. Instead they take a single argument in the form of:
export function get({ params, request }) {
//...
}
Update your code to remove this warning.`)
}
const context = {
request,
params
};
const proxy = new Proxy(context, {
get(target, prop) {
if(prop in target) {
return Reflect.get(target, prop);
} else if(prop in params) {
// eslint-disable-next-line no-console
console.warn(`
API routes no longer pass params as the first argument. Instead an object containing a params property is provided in the form of:
export function get({ params }) {
// ...
}
Update your code to remove this warning.`);
return Reflect.get(params, prop);
} else {
return undefined;
}
}
}) as APIContext & Params;
return await handler.call(mod, proxy, request);
}
async function replaceHeadInjection(result: SSRResult, html: string): Promise<string> {

View file

@ -0,0 +1,44 @@
import { expect } from 'chai';
import * as cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
describe('API routes', () => {
let fixture;
before(async () => {
fixture = await loadFixture({ root: './fixtures/api-routes/' });
await fixture.build();
});
describe('Deprecated API', () => {
it('two argument supported', async () => {
const one = JSON.parse(await fixture.readFile('/old-api/twoarg/one.json'));
expect(one).to.deep.equal({
param: 'one',
pathname: '/old-api/twoarg/one.json'
});
const two = JSON.parse(await fixture.readFile('/old-api/twoarg/two.json'));
expect(two).to.deep.equal({
param: 'two',
pathname: '/old-api/twoarg/two.json'
});
});
it('param first argument is supported', async () => {
const one = JSON.parse(await fixture.readFile('/old-api/onearg/one.json'));
expect(one).to.deep.equal({
param: 'one'
});
});
});
describe('1.0 API', () => {
it('Receives a context argument', async () => {
const one = JSON.parse(await fixture.readFile('/context/data/one.json'));
expect(one).to.deep.equal({
param: 'one',
pathname: '/context/data/one.json'
});
});
});
});

View file

@ -0,0 +1,24 @@
export function getStaticPaths() {
return [
{
params: {
param: 'one'
}
},
{
params: {
param: 'two'
}
},
]
}
export function get({ params, request }) {
return {
body: JSON.stringify({
param: params.param,
pathname: new URL(request.url).pathname
})
};
}

View file

@ -0,0 +1,23 @@
export function getStaticPaths() {
return [
{
params: {
param: 'one'
}
},
{
params: {
param: 'two'
}
},
]
}
export function get(params) {
return {
body: JSON.stringify({
param: params.param
})
};
}

View file

@ -0,0 +1,24 @@
export function getStaticPaths() {
return [
{
params: {
param: 'one'
}
},
{
params: {
param: 'two'
}
},
]
}
export function get(params, request) {
return {
body: JSON.stringify({
param: params.param,
pathname: new URL(request.url).pathname
})
};
}

View file

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