Add new fields to API route context (#4986)
* Add new fields to API route context * Add props and redirect * Pass custom redirect status code * Correctly pass props in api routes * Add better docs * Add test * Fix build * Add constants file * Add links to jsdoc * Workaround lint issue * Thanks Chris Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> * Missed one doc change Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> * Add more detail to the changesets * Strict redirect status type Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> Co-authored-by: Matthew Phillips <matthew@skypack.dev>
This commit is contained in:
parent
07d16ff43c
commit
ebd364e392
17 changed files with 257 additions and 37 deletions
19
.changeset/fifty-ads-march.md
Normal file
19
.changeset/fifty-ads-march.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
'astro': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
## New properties for API routes
|
||||||
|
|
||||||
|
In API routes, you can now get the `site`, `generator`, `url`, `clientAddress`, `props`, and `redirect` fields on the APIContext, which is the first parameter passed to an API route. This was done to make the APIContext more closely align with the `Astro` global in .astro pages.
|
||||||
|
|
||||||
|
For example, here's how you might use the `clientAddress`, which is the user's IP address, to selectively allow users.
|
||||||
|
|
||||||
|
```js
|
||||||
|
export function post({ clientAddress, request, redirect }) {
|
||||||
|
if(!allowList.has(clientAddress)) {
|
||||||
|
return redirect('/not-allowed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out the docs for more information on the newly available fields: https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes
|
14
.changeset/selfish-foxes-bake.md
Normal file
14
.changeset/selfish-foxes-bake.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
'astro': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
## Support passing a custom status code for Astro.redirect
|
||||||
|
|
||||||
|
New in this minor is the ability to pass a status code to `Astro.redirect`. By default it uses `302` but now you can pass another code as the second argument:
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
// This page was moved
|
||||||
|
return Astro.redirect('/posts/new-post-name', 301);
|
||||||
|
---
|
||||||
|
```
|
|
@ -94,7 +94,8 @@ export interface BuildConfig {
|
||||||
* [Astro reference](https://docs.astro.build/reference/api-reference/#astro-global)
|
* [Astro reference](https://docs.astro.build/reference/api-reference/#astro-global)
|
||||||
*/
|
*/
|
||||||
export interface AstroGlobal<Props extends Record<string, any> = Record<string, any>>
|
export interface AstroGlobal<Props extends Record<string, any> = Record<string, any>>
|
||||||
extends AstroGlobalPartial {
|
extends AstroGlobalPartial,
|
||||||
|
AstroSharedContext<Props> {
|
||||||
/**
|
/**
|
||||||
* Canonical URL of the current page.
|
* Canonical URL of the current page.
|
||||||
* @deprecated Use `Astro.url` instead.
|
* @deprecated Use `Astro.url` instead.
|
||||||
|
@ -107,21 +108,13 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
canonicalURL: URL;
|
canonicalURL: URL;
|
||||||
/** The address (usually IP address) of the user. Used with SSR only.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
clientAddress: string;
|
|
||||||
/**
|
/**
|
||||||
* A full URL object of the request URL.
|
* A full URL object of the request URL.
|
||||||
* Equivalent to: `new URL(Astro.request.url)`
|
* Equivalent to: `new URL(Astro.request.url)`
|
||||||
*
|
*
|
||||||
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#url)
|
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#url)
|
||||||
*/
|
*/
|
||||||
/**
|
url: AstroSharedContext['url'];
|
||||||
* Utility for getting and setting cookies values.
|
|
||||||
*/
|
|
||||||
cookies: AstroCookies;
|
|
||||||
url: URL;
|
|
||||||
/** Parameters passed to a dynamic page generated using [getStaticPaths](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
|
/** Parameters passed to a dynamic page generated using [getStaticPaths](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
|
||||||
*
|
*
|
||||||
* Example usage:
|
* Example usage:
|
||||||
|
@ -138,9 +131,9 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
|
||||||
* <h1>{id}</h1>
|
* <h1>{id}</h1>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#params)
|
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#astroparams)
|
||||||
*/
|
*/
|
||||||
params: Params;
|
params: AstroSharedContext['params'];
|
||||||
/** List of props passed to this component
|
/** List of props passed to this component
|
||||||
*
|
*
|
||||||
* A common way to get specific props is through [destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), ex:
|
* A common way to get specific props is through [destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), ex:
|
||||||
|
@ -150,7 +143,7 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
|
||||||
*
|
*
|
||||||
* [Astro reference](https://docs.astro.build/en/core-concepts/astro-components/#component-props)
|
* [Astro reference](https://docs.astro.build/en/core-concepts/astro-components/#component-props)
|
||||||
*/
|
*/
|
||||||
props: Props;
|
props: AstroSharedContext<Props>['props'];
|
||||||
/** Information about the current request. This is a standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object
|
/** Information about the current request. This is a standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object
|
||||||
*
|
*
|
||||||
* For example, to get a URL object of the current URL, you can use:
|
* For example, to get a URL object of the current URL, you can use:
|
||||||
|
@ -184,11 +177,11 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
|
||||||
*
|
*
|
||||||
* [Astro reference](https://docs.astro.build/en/guides/server-side-rendering/#astroredirect)
|
* [Astro reference](https://docs.astro.build/en/guides/server-side-rendering/#astroredirect)
|
||||||
*/
|
*/
|
||||||
redirect(path: string): Response;
|
redirect: AstroSharedContext['redirect'];
|
||||||
/**
|
/**
|
||||||
* The <Astro.self /> element allows a component to reference itself recursively.
|
* The <Astro.self /> element allows a component to reference itself recursively.
|
||||||
*
|
*
|
||||||
* [Astro reference](https://docs.astro.build/en/guides/server-side-rendering/#astroself)
|
* [Astro reference](https://docs.astro.build/en/guides/api-reference/#astroself)
|
||||||
*/
|
*/
|
||||||
self: AstroComponentFactory;
|
self: AstroComponentFactory;
|
||||||
/** Utility functions for modifying an Astro component’s slotted children
|
/** Utility functions for modifying an Astro component’s slotted children
|
||||||
|
@ -1077,8 +1070,6 @@ export type PaginateFunction = (data: any[], args?: PaginateOptions) => GetStati
|
||||||
|
|
||||||
export type Params = Record<string, string | number | undefined>;
|
export type Params = Record<string, string | number | undefined>;
|
||||||
|
|
||||||
export type Props = Record<string, unknown>;
|
|
||||||
|
|
||||||
export interface AstroAdapter {
|
export interface AstroAdapter {
|
||||||
name: string;
|
name: string;
|
||||||
serverEntrypoint?: string;
|
serverEntrypoint?: string;
|
||||||
|
@ -1088,12 +1079,113 @@ export interface AstroAdapter {
|
||||||
|
|
||||||
type Body = string;
|
type Body = string;
|
||||||
|
|
||||||
export interface APIContext {
|
// Shared types between `Astro` global and API context object
|
||||||
|
interface AstroSharedContext<Props extends Record<string, any> = Record<string, any>> {
|
||||||
|
/**
|
||||||
|
* The address (usually IP address) of the user. Used with SSR only.
|
||||||
|
*/
|
||||||
|
clientAddress: string;
|
||||||
|
/**
|
||||||
|
* Utility for getting and setting the values of cookies.
|
||||||
|
*/
|
||||||
cookies: AstroCookies;
|
cookies: AstroCookies;
|
||||||
params: Params;
|
/**
|
||||||
|
* Information about the current request. This is a standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object
|
||||||
|
*/
|
||||||
request: Request;
|
request: Request;
|
||||||
|
/**
|
||||||
|
* A full URL object of the request URL.
|
||||||
|
*/
|
||||||
|
url: URL;
|
||||||
|
/**
|
||||||
|
* Route parameters for this request if this is a dynamic route.
|
||||||
|
*/
|
||||||
|
params: Params;
|
||||||
|
/**
|
||||||
|
* List of props returned for this path by `getStaticPaths` (**Static Only**).
|
||||||
|
*/
|
||||||
|
props: Props;
|
||||||
|
/**
|
||||||
|
* Redirect to another page (**SSR Only**).
|
||||||
|
*/
|
||||||
|
redirect(path: string, status?: 301 | 302 | 308): Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface APIContext<Props extends Record<string, any> = Record<string, any>>
|
||||||
|
extends AstroSharedContext<Props> {
|
||||||
|
site: URL | undefined;
|
||||||
|
generator: string;
|
||||||
|
/**
|
||||||
|
* A full URL object of the request URL.
|
||||||
|
* Equivalent to: `new URL(request.url)`
|
||||||
|
*/
|
||||||
|
url: AstroSharedContext['url'];
|
||||||
|
/**
|
||||||
|
* Parameters matching the page’s dynamic route pattern.
|
||||||
|
* In static builds, this will be the `params` generated by `getStaticPaths`.
|
||||||
|
* In SSR builds, this can be any path segments matching the dynamic route pattern.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* export function getStaticPaths() {
|
||||||
|
* return [
|
||||||
|
* { params: { id: '0' }, props: { name: 'Sarah' } },
|
||||||
|
* { params: { id: '1' }, props: { name: 'Chris' } },
|
||||||
|
* { params: { id: '2' }, props: { name: 'Fuzzy' } },
|
||||||
|
* ];
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* export async function get({ params }) {
|
||||||
|
* return {
|
||||||
|
* body: `Hello user ${params.id}!`,
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* [context reference](https://docs.astro.build/en/guides/api-reference/#contextparams)
|
||||||
|
*/
|
||||||
|
params: AstroSharedContext['params'];
|
||||||
|
/**
|
||||||
|
* List of props passed from `getStaticPaths`. Only available to static builds.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* export function getStaticPaths() {
|
||||||
|
* return [
|
||||||
|
* { params: { id: '0' }, props: { name: 'Sarah' } },
|
||||||
|
* { params: { id: '1' }, props: { name: 'Chris' } },
|
||||||
|
* { params: { id: '2' }, props: { name: 'Fuzzy' } },
|
||||||
|
* ];
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* export function get({ props }) {
|
||||||
|
* return {
|
||||||
|
* body: `Hello ${props.name}!`,
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* [context reference](https://docs.astro.build/en/guides/api-reference/#contextprops)
|
||||||
|
*/
|
||||||
|
props: AstroSharedContext<Props>['props'];
|
||||||
|
/**
|
||||||
|
* Redirect to another page. Only available in SSR builds.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* ```ts
|
||||||
|
* // src/pages/secret.ts
|
||||||
|
* export function get({ redirect }) {
|
||||||
|
* return redirect('/login');
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* [context reference](https://docs.astro.build/en/guides/api-reference/#contextredirect)
|
||||||
|
*/
|
||||||
|
redirect: AstroSharedContext['redirect'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Props = Record<string, unknown>;
|
||||||
|
|
||||||
export interface EndpointOutput {
|
export interface EndpointOutput {
|
||||||
body: Body;
|
body: Body;
|
||||||
encoding?: BufferEncoding;
|
encoding?: BufferEncoding;
|
||||||
|
|
|
@ -21,7 +21,8 @@ import { enableVerboseLogging, nodeLogDestination } from '../core/logger/node.js
|
||||||
import { formatConfigErrorMessage, formatErrorMessage, printHelp } from '../core/messages.js';
|
import { formatConfigErrorMessage, formatErrorMessage, printHelp } from '../core/messages.js';
|
||||||
import { appendForwardSlash } from '../core/path.js';
|
import { appendForwardSlash } from '../core/path.js';
|
||||||
import preview from '../core/preview/index.js';
|
import preview from '../core/preview/index.js';
|
||||||
import { ASTRO_VERSION, createSafeError } from '../core/util.js';
|
import { ASTRO_VERSION } from '../core/constants.js';
|
||||||
|
import { createSafeError } from '../core/util.js';
|
||||||
import * as event from '../events/index.js';
|
import * as event from '../events/index.js';
|
||||||
import { eventConfigError, eventError, telemetry } from '../events/index.js';
|
import { eventConfigError, eventError, telemetry } from '../events/index.js';
|
||||||
import { check } from './check/index.js';
|
import { check } from './check/index.js';
|
||||||
|
|
2
packages/astro/src/core/constants.ts
Normal file
2
packages/astro/src/core/constants.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// process.env.PACKAGE_VERSION is injected when we build and publish the astro package.
|
||||||
|
export const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development';
|
|
@ -8,5 +8,7 @@ export async function call(ssrOpts: SSROptions) {
|
||||||
return await callEndpoint(mod as unknown as EndpointHandler, {
|
return await callEndpoint(mod as unknown as EndpointHandler, {
|
||||||
...ssrOpts,
|
...ssrOpts,
|
||||||
ssr: ssrOpts.settings.config.output === 'server',
|
ssr: ssrOpts.settings.config.output === 'server',
|
||||||
|
site: ssrOpts.settings.config.site,
|
||||||
|
adapterName: ssrOpts.settings.config.adapter?.name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ import type { RenderOptions } from '../render/core';
|
||||||
import { renderEndpoint } from '../../runtime/server/index.js';
|
import { renderEndpoint } from '../../runtime/server/index.js';
|
||||||
import { AstroCookies, attachToResponse } from '../cookies/index.js';
|
import { AstroCookies, attachToResponse } from '../cookies/index.js';
|
||||||
import { getParamsAndProps, GetParamsAndPropsError } from '../render/core.js';
|
import { getParamsAndProps, GetParamsAndPropsError } from '../render/core.js';
|
||||||
|
import { ASTRO_VERSION } from '../constants.js';
|
||||||
|
|
||||||
|
const clientAddressSymbol = Symbol.for('astro.clientAddress');
|
||||||
|
|
||||||
export type EndpointOptions = Pick<
|
export type EndpointOptions = Pick<
|
||||||
RenderOptions,
|
RenderOptions,
|
||||||
|
@ -17,6 +20,7 @@ export type EndpointOptions = Pick<
|
||||||
| 'site'
|
| 'site'
|
||||||
| 'ssr'
|
| 'ssr'
|
||||||
| 'status'
|
| 'status'
|
||||||
|
| 'adapterName'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type EndpointCallResult =
|
type EndpointCallResult =
|
||||||
|
@ -30,11 +34,50 @@ type EndpointCallResult =
|
||||||
response: Response;
|
response: Response;
|
||||||
};
|
};
|
||||||
|
|
||||||
function createAPIContext(request: Request, params: Params): APIContext {
|
function createAPIContext({
|
||||||
|
request,
|
||||||
|
params,
|
||||||
|
site,
|
||||||
|
props,
|
||||||
|
adapterName,
|
||||||
|
}: {
|
||||||
|
request: Request;
|
||||||
|
params: Params;
|
||||||
|
site?: string;
|
||||||
|
props: Record<string, any>;
|
||||||
|
adapterName?: string;
|
||||||
|
}): APIContext {
|
||||||
return {
|
return {
|
||||||
cookies: new AstroCookies(request),
|
cookies: new AstroCookies(request),
|
||||||
request,
|
request,
|
||||||
params,
|
params,
|
||||||
|
site: site ? new URL(site) : undefined,
|
||||||
|
generator: `Astro v${ASTRO_VERSION}`,
|
||||||
|
props,
|
||||||
|
redirect(path, status) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: status || 302,
|
||||||
|
headers: {
|
||||||
|
Location: path,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
url: new URL(request.url),
|
||||||
|
get clientAddress() {
|
||||||
|
if (!(clientAddressSymbol in request)) {
|
||||||
|
if (adapterName) {
|
||||||
|
throw new Error(
|
||||||
|
`clientAddress is not available in the ${adapterName} adapter. File an issue with the adapter to add support.`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`clientAddress is not available in your environment. Ensure that you are using an SSR adapter that supports this feature.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Reflect.get(request, clientAddressSymbol);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,9 +92,15 @@ export async function call(
|
||||||
`[getStaticPath] route pattern matched, but no matching static path found. (${opts.pathname})`
|
`[getStaticPath] route pattern matched, but no matching static path found. (${opts.pathname})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const [params] = paramsAndPropsResp;
|
const [params, props] = paramsAndPropsResp;
|
||||||
|
|
||||||
const context = createAPIContext(opts.request, params);
|
const context = createAPIContext({
|
||||||
|
request: opts.request,
|
||||||
|
params,
|
||||||
|
props,
|
||||||
|
site: opts.site,
|
||||||
|
adapterName: opts.adapterName,
|
||||||
|
});
|
||||||
const response = await renderEndpoint(mod, context, opts.ssr);
|
const response = await renderEndpoint(mod, context, opts.ssr);
|
||||||
|
|
||||||
if (response instanceof Response) {
|
if (response instanceof Response) {
|
||||||
|
|
|
@ -68,7 +68,7 @@ export async function getParamsAndProps(
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenderOptions {
|
export interface RenderOptions {
|
||||||
adapterName: string | undefined;
|
adapterName?: string;
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
links: Set<SSRElement>;
|
links: Set<SSRElement>;
|
||||||
styles?: Set<SSRElement>;
|
styles?: Set<SSRElement>;
|
||||||
|
|
|
@ -166,7 +166,8 @@ export function createResult(args: CreateResultArgs): SSRResult {
|
||||||
) {
|
) {
|
||||||
const astroSlots = new Slots(result, slots, args.logging);
|
const astroSlots = new Slots(result, slots, args.logging);
|
||||||
|
|
||||||
const Astro = {
|
const Astro: AstroGlobal = {
|
||||||
|
// @ts-expect-error set prototype
|
||||||
__proto__: astroGlobal,
|
__proto__: astroGlobal,
|
||||||
get clientAddress() {
|
get clientAddress() {
|
||||||
if (!(clientAddressSymbol in request)) {
|
if (!(clientAddressSymbol in request)) {
|
||||||
|
@ -196,9 +197,9 @@ export function createResult(args: CreateResultArgs): SSRResult {
|
||||||
request,
|
request,
|
||||||
url,
|
url,
|
||||||
redirect: args.ssr
|
redirect: args.ssr
|
||||||
? (path: string) => {
|
? (path, status) => {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: status || 302,
|
||||||
headers: {
|
headers: {
|
||||||
Location: path,
|
Location: path,
|
||||||
},
|
},
|
||||||
|
@ -237,9 +238,9 @@ ${extra}`
|
||||||
// Intentionally return an empty string so that it is not relied upon.
|
// Intentionally return an empty string so that it is not relied upon.
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
response,
|
response: response as AstroGlobal['response'],
|
||||||
slots: astroSlots,
|
slots: astroSlots as unknown as AstroGlobal['slots'],
|
||||||
} as unknown as AstroGlobal;
|
};
|
||||||
|
|
||||||
Object.defineProperty(Astro, 'canonicalURL', {
|
Object.defineProperty(Astro, 'canonicalURL', {
|
||||||
get: function () {
|
get: function () {
|
||||||
|
|
|
@ -8,9 +8,6 @@ import type { ErrorPayload, ViteDevServer } from 'vite';
|
||||||
import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro';
|
import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro';
|
||||||
import { prependForwardSlash, removeTrailingForwardSlash } from './path.js';
|
import { prependForwardSlash, removeTrailingForwardSlash } from './path.js';
|
||||||
|
|
||||||
// process.env.PACKAGE_VERSION is injected when we build and publish the astro package.
|
|
||||||
export const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development';
|
|
||||||
|
|
||||||
/** Returns true if argument is an object of any prototype/class (but not null). */
|
/** Returns true if argument is an object of any prototype/class (but not null). */
|
||||||
export function isObject(value: unknown): value is Record<string, any> {
|
export function isObject(value: unknown): value is Record<string, any> {
|
||||||
return typeof value === 'object' && value != null;
|
return typeof value === 'object' && value != null;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { AstroTelemetry } from '@astrojs/telemetry';
|
import { AstroTelemetry } from '@astrojs/telemetry';
|
||||||
import { createRequire } from 'module';
|
import { createRequire } from 'module';
|
||||||
import { ASTRO_VERSION } from '../core/util.js';
|
import { ASTRO_VERSION } from '../core/constants.js';
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
function getViteVersion() {
|
function getViteVersion() {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import type { AstroGlobalPartial } from '../../@types/astro';
|
import type { AstroGlobalPartial } from '../../@types/astro';
|
||||||
|
import { ASTRO_VERSION } from '../../core/constants.js';
|
||||||
// process.env.PACKAGE_VERSION is injected when we build and publish the astro package.
|
|
||||||
const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development';
|
|
||||||
|
|
||||||
/** Create the Astro.fetchContent() runtime function. */
|
/** Create the Astro.fetchContent() runtime function. */
|
||||||
function createDeprecatedFetchContentFn() {
|
function createDeprecatedFetchContentFn() {
|
||||||
|
|
8
packages/astro/test/fixtures/ssr-api-route/astro.config.mjs
vendored
Normal file
8
packages/astro/test/fixtures/ssr-api-route/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import node from '@astrojs/node';
|
||||||
|
|
||||||
|
// https://astro.build/config
|
||||||
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
|
adapter: node(),
|
||||||
|
});
|
|
@ -3,6 +3,7 @@
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@astrojs/node": "^1.1.0",
|
||||||
"astro": "workspace:*"
|
"astro": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js
vendored
Normal file
18
packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/**
|
||||||
|
* @param {import('astro').APIContext} api
|
||||||
|
*/
|
||||||
|
export function get(ctx) {
|
||||||
|
return {
|
||||||
|
body: JSON.stringify({
|
||||||
|
cookiesExist: !!ctx.cookies,
|
||||||
|
requestExist: !!ctx.request,
|
||||||
|
redirectExist: !!ctx.redirect,
|
||||||
|
propsExist: !!ctx.props,
|
||||||
|
params: ctx.params,
|
||||||
|
site: ctx.site?.toString(),
|
||||||
|
generator: ctx.generator,
|
||||||
|
url: ctx.url.toString(),
|
||||||
|
clientAddress: ctx.clientAddress,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
|
@ -35,6 +35,22 @@ describe('API routes in SSR', () => {
|
||||||
expect(body.length).to.equal(3);
|
expect(body.length).to.equal(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Has valid api context', async () => {
|
||||||
|
const app = await fixture.loadTestAdapterApp();
|
||||||
|
const request = new Request('http://example.com/context/any');
|
||||||
|
const response = await app.render(request);
|
||||||
|
expect(response.status).to.equal(200);
|
||||||
|
const data = await response.json();
|
||||||
|
expect(data.cookiesExist).to.equal(true);
|
||||||
|
expect(data.requestExist).to.equal(true);
|
||||||
|
expect(data.redirectExist).to.equal(true);
|
||||||
|
expect(data.propsExist).to.equal(true);
|
||||||
|
expect(data.params).to.deep.equal({ param: 'any' });
|
||||||
|
expect(data.generator).to.match(/^Astro v/);
|
||||||
|
expect(data.url).to.equal('http://example.com/context/any');
|
||||||
|
expect(data.clientAddress).to.equal('0.0.0.0');
|
||||||
|
});
|
||||||
|
|
||||||
describe('API Routes - Dev', () => {
|
describe('API Routes - Dev', () => {
|
||||||
let devServer;
|
let devServer;
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
|
|
@ -2161,8 +2161,10 @@ importers:
|
||||||
|
|
||||||
packages/astro/test/fixtures/ssr-api-route:
|
packages/astro/test/fixtures/ssr-api-route:
|
||||||
specifiers:
|
specifiers:
|
||||||
|
'@astrojs/node': ^1.1.0
|
||||||
astro: workspace:*
|
astro: workspace:*
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@astrojs/node': link:../../../../integrations/node
|
||||||
astro: link:../../..
|
astro: link:../../..
|
||||||
|
|
||||||
packages/astro/test/fixtures/ssr-api-route-custom-404:
|
packages/astro/test/fixtures/ssr-api-route-custom-404:
|
||||||
|
|
Loading…
Reference in a new issue