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:
parent
d825d376f8
commit
6643a3931d
9 changed files with 179 additions and 3 deletions
5
.changeset/fast-dolls-eat.md
Normal file
5
.changeset/fast-dolls-eat.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Implements the Dynamic Route API RFC
|
|
@ -856,12 +856,27 @@ export interface AstroAdapter {
|
||||||
args?: any;
|
args?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface APIContext {
|
||||||
|
params: Params;
|
||||||
|
request: Request;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EndpointOutput<Output extends Body = Body> {
|
export interface EndpointOutput<Output extends Body = Body> {
|
||||||
body: Output;
|
body: Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface APIRoute {
|
||||||
|
(context: APIContext): EndpointOutput | Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* Use { context: APIRouteContext } object instead.
|
||||||
|
*/
|
||||||
|
(params: Params, request: Request): EndpointOutput | Response;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EndpointHandler {
|
export interface EndpointHandler {
|
||||||
[method: string]: (params: any, request: Request) => EndpointOutput | Response;
|
[method: string]: APIRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AstroRenderer {
|
export interface AstroRenderer {
|
||||||
|
|
|
@ -52,6 +52,7 @@ export async function callGetStaticPaths({
|
||||||
|
|
||||||
const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed;
|
const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed;
|
||||||
keyedStaticPaths.keyed = new Map<string, GetStaticPathsItem>();
|
keyedStaticPaths.keyed = new Map<string, GetStaticPathsItem>();
|
||||||
|
|
||||||
for (const sp of keyedStaticPaths) {
|
for (const sp of keyedStaticPaths) {
|
||||||
const paramsKey = stringifyParams(sp.params);
|
const paramsKey = stringifyParams(sp.params);
|
||||||
keyedStaticPaths.keyed.set(paramsKey, sp);
|
keyedStaticPaths.keyed.set(paramsKey, sp);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type {
|
import type {
|
||||||
|
APIContext,
|
||||||
AstroComponentMetadata,
|
AstroComponentMetadata,
|
||||||
AstroGlobalPartial,
|
AstroGlobalPartial,
|
||||||
EndpointHandler,
|
EndpointHandler,
|
||||||
|
@ -468,7 +469,46 @@ export async function renderEndpoint(mod: EndpointHandler, request: Request, par
|
||||||
`Endpoint handler not found! Expected an exported function for "${chosenMethod}"`
|
`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> {
|
async function replaceHeadInjection(result: SSRResult, html: string): Promise<string> {
|
||||||
|
|
44
packages/astro/test/api-routes.test.js
Normal file
44
packages/astro/test/api-routes.test.js
Normal 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'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
24
packages/astro/test/fixtures/api-routes/src/pages/context/data/[param].json.js
vendored
Normal file
24
packages/astro/test/fixtures/api-routes/src/pages/context/data/[param].json.js
vendored
Normal 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
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
23
packages/astro/test/fixtures/api-routes/src/pages/old-api/onearg/[param].json.js
vendored
Normal file
23
packages/astro/test/fixtures/api-routes/src/pages/old-api/onearg/[param].json.js
vendored
Normal 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
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
24
packages/astro/test/fixtures/api-routes/src/pages/old-api/twoarg/[param].json.js
vendored
Normal file
24
packages/astro/test/fixtures/api-routes/src/pages/old-api/twoarg/[param].json.js
vendored
Normal 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
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
export function get(params) {
|
export function get({ params }) {
|
||||||
return {
|
return {
|
||||||
body: JSON.stringify(params)
|
body: JSON.stringify(params)
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue