Skip to content

Commit

Permalink
fix(middleware): instantiate locals if the adapter does not (#8800)
Browse files Browse the repository at this point in the history
  • Loading branch information
lilnasy authored Oct 12, 2023
1 parent 3bef32f commit 3917296
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 18 deletions.
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

0 comments on commit 3917296

Please sign in to comment.