Skip to content
This repository was archived by the owner on May 10, 2021. It is now read-only.

Commit c537545

Browse files
committed
Expose event + context of Netlify Functions on the req object
When a page is being SSR-ed by a Netlify Function, allow users to access the function's event and context parameters. These can be accessed as a property on the `req` object in all SSR-ed pages and in API routes: - req.netlifyFunction.event - req.netlifyFunction.context This allows users to access/leverage Netlify identity for their Next.js page. See: #20 It also allows users to modify the callbackWaitsForEmptyEventLoop behavior. See: #66 (comment))
1 parent 1e35de0 commit c537545

File tree

6 files changed

+72
-6
lines changed

6 files changed

+72
-6
lines changed

cypress/fixtures/pages/api/context.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default async function context(req, res) {
2+
res.json({ req, res });
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const Context = ({ context }) => <pre>{JSON.stringify(context, 2, " ")}</pre>;
2+
3+
export const getServerSideProps = async (context) => {
4+
return {
5+
props: {
6+
context,
7+
},
8+
};
9+
};
10+
11+
export default Context;

cypress/integration/default_spec.js

+46
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,31 @@ describe("getInitialProps", () => {
136136
});
137137

138138
describe("getServerSideProps", () => {
139+
it("exposes function context on the req object", () => {
140+
cy.visit("/getServerSideProps/context");
141+
142+
cy.get("pre")
143+
.first()
144+
.then((json) => {
145+
const {
146+
req: {
147+
netlifyFunction: { event, context },
148+
},
149+
} = JSON.parse(json.html());
150+
151+
expect(event).to.have.property("path", "/getServerSideProps/context");
152+
expect(event).to.have.property("httpMethod", "GET");
153+
expect(event).to.have.property("headers");
154+
expect(event).to.have.property("multiValueHeaders");
155+
expect(event).to.have.property("isBase64Encoded");
156+
expect(context.done).to.be.undefined;
157+
expect(context.getRemainingTimeInMillis).to.be.undefined;
158+
expect(context).to.have.property("awsRequestId");
159+
expect(context).to.have.property("callbackWaitsForEmptyEventLoop");
160+
expect(context).to.have.property("clientContext");
161+
});
162+
});
163+
139164
context("with static route", () => {
140165
it("loads TV shows", () => {
141166
cy.visit("/getServerSideProps/static");
@@ -534,6 +559,27 @@ describe("API endpoint", () => {
534559
cy.get("h1").should("contain", "Show #999");
535560
cy.get("p").should("contain", "Flash Gordon");
536561
});
562+
563+
it("exposes function context on the req object", () => {
564+
cy.request("/api/context").then((response) => {
565+
const {
566+
req: {
567+
netlifyFunction: { event, context },
568+
},
569+
} = response.body;
570+
571+
expect(event).to.have.property("path", "/api/context");
572+
expect(event).to.have.property("httpMethod", "GET");
573+
expect(event).to.have.property("headers");
574+
expect(event).to.have.property("multiValueHeaders");
575+
expect(event).to.have.property("isBase64Encoded");
576+
expect(context.done).to.be.undefined;
577+
expect(context.getRemainingTimeInMillis).to.be.undefined;
578+
expect(context).to.have.property("awsRequestId");
579+
expect(context).to.have.property("callbackWaitsForEmptyEventLoop");
580+
expect(context).to.have.property("clientContext");
581+
});
582+
});
537583
});
538584

539585
describe("Preview Mode", () => {

lib/templates/createRequestObject.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const http = require("http");
66
// Based on API Gateway Lambda Compat
77
// Source: https://github.com/serverless-nextjs/serverless-next.js/blob/master/packages/compat-layers/apigw-lambda-compat/lib/compatLayer.js
88

9-
const createRequestObject = ({ event }) => {
9+
const createRequestObject = ({ event, context }) => {
1010
const {
1111
requestContext = {},
1212
path = "",
@@ -52,6 +52,14 @@ const createRequestObject = ({ event }) => {
5252
req.rawHeaders = [];
5353
req.headers = {};
5454

55+
// Expose Netlify Function event and callback on request object.
56+
// This makes it possible to access the clientContext, for example.
57+
// See: https://github.com/netlify/next-on-netlify/issues/20
58+
// It also allows users to change the behavior of waiting for empty event
59+
// loop.
60+
// See: https://github.com/netlify/next-on-netlify/issues/66#issuecomment-719988804
61+
req.netlifyFunction = { event, context };
62+
5563
for (const key of Object.keys(multiValueHeaders)) {
5664
for (const value of multiValueHeaders[key]) {
5765
req.rawHeaders.push(key);

lib/templates/netlifyFunction.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ exports.handler = async (event, context, callback) => {
1616
console.log("[request]", path);
1717

1818
// Render the Next.js page
19-
const response = await renderNextPage({
20-
...event,
21-
});
19+
const response = await renderNextPage({ event, context });
2220

2321
// Convert header values to string. Netlify does not support integers as
2422
// header values. See: https://github.com/netlify/cli/issues/451

lib/templates/renderNextPage.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ const createRequestObject = require("./createRequestObject");
44
const createResponseObject = require("./createResponseObject");
55

66
// Render the Next.js page
7-
const renderNextPage = (event) => {
7+
const renderNextPage = ({ event, context }) => {
88
// The Next.js page is rendered inside a promise that is resolved when the
99
// Next.js page ends the response via `res.end()`
1010
const promise = new Promise((resolve) => {
1111
// Create a Next.js-compatible request and response object
1212
// These mock the ClientRequest and ServerResponse classes from node http
1313
// See: https://nodejs.org/api/http.html
14-
const req = createRequestObject({ event });
14+
const req = createRequestObject({ event, context });
1515
const res = createResponseObject({
1616
onResEnd: (response) => resolve(response),
1717
});

0 commit comments

Comments
 (0)