Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(middleware): instantiate locals if the adapter does not #8800

Merged
merged 5 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/large-colts-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixed an issue where attempting to assign a variable onto locals threw an error.
33 changes: 20 additions & 13 deletions packages/astro/src/core/endpoint/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ export function createAPIContext({
ResponseWithEncoding,
url: new URL(request.url),
get clientAddress() {
if (!(clientAddressSymbol in request)) {
if (clientAddressSymbol in request) {
return Reflect.get(request, clientAddressSymbol) as string;
}
if (adapterName) {
throw new AstroError({
...AstroErrorData.ClientAddressNotAvailable,
Expand All @@ -66,26 +68,31 @@ export function createAPIContext({
} else {
throw new AstroError(AstroErrorData.StaticClientAddressNotAvailable);
}
}

return Reflect.get(request, clientAddressSymbol);
},
} as APIContext;

// We define a custom property, so we can check the value passed to locals
Object.defineProperty(context, 'locals', {
enumerable: true,
get() {
return Reflect.get(request, clientLocalsSymbol);
get locals() {
let locals = Reflect.get(request, clientLocalsSymbol)

if (locals === undefined) {
locals = {}
Reflect.set(request, clientLocalsSymbol, locals)
}

if (typeof locals !== 'object') {
throw new AstroError(AstroErrorData.LocalsNotAnObject);
}

return locals;
},
set(val) {
// We define a custom property, so we can check the value passed to locals
set locals(val) {
if (typeof val !== 'object') {
throw new AstroError(AstroErrorData.LocalsNotAnObject);
} else {
Reflect.set(request, clientLocalsSymbol, val);
}
},
});
} satisfies APIContext;

return context;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineMiddleware } from 'astro:middleware';

export const onRequest = defineMiddleware(({ url, locals }, next) => {
if (url.pathname === "/from-astro-middleware") locals.foo = "baz";
return next();
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

export async function post({ locals }) {
let out = { ...locals };
export async function POST({ locals }) {
const out = { ...locals };

return new Response(JSON.stringify(out), {
headers: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
const { foo } = Astro.locals;
---
<h1>{foo}</h1>
33 changes: 30 additions & 3 deletions packages/integrations/node/test/locals.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ describe('API routes', () => {
await fixture.build();
});

it('Can render locals in page', async () => {
it('Can use locals added by node middleware', async () => {
const { handler } = await import('./fixtures/locals/dist/server/entry.mjs');
let { req, res, text } = createRequestAndResponse({
method: 'POST',
url: '/foo',
url: '/from-node-middleware',
});

let locals = { foo: 'bar' };
Expand All @@ -32,6 +31,34 @@ describe('API routes', () => {
expect(html).to.contain('<h1>bar</h1>');
});

it('Throws an error when provided non-objects as locals', async () => {
const { handler } = await import('./fixtures/locals/dist/server/entry.mjs');
let { req, res, done } = createRequestAndResponse({
url: '/from-node-middleware',
});

handler(req, res, undefined, "locals");
req.send();

await done;
expect(res).to.deep.include({ statusCode: 500 });
});

it('Can use locals added by astro middleware', async () => {
const { handler } = await import('./fixtures/locals/dist/server/entry.mjs');

const { req, res, text } = createRequestAndResponse({
url: '/from-astro-middleware',
});

handler(req, res, () => {});
req.send();

const html = await text();

expect(html).to.contain('<h1>baz</h1>');
});

it('Can access locals in API', async () => {
const { handler } = await import('./fixtures/locals/dist/server/entry.mjs');
let { req, res, done } = createRequestAndResponse({
Expand Down