Skip to content
This repository was archived by the owner on Jan 28, 2025. It is now read-only.

Commit eb9a6f4

Browse files
feat: add HEAD http event to NextPages (#43)
* feat: add head http event to NextPages * test: add integration tests for api gateway http method resources * docs: update documentation
1 parent c0967c8 commit eb9a6f4

File tree

4 files changed

+187
-46
lines changed

4 files changed

+187
-46
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ events:
133133
- http:
134134
path: pageName # home, about, etc. Unless is the index page which is served at /
135135
method: get
136+
- http:
137+
path: pageName # home, about, etc. Unless is the index page which is served at /
138+
method: head
136139
```
137140

138141
If you need to change the default configuration, such as `memorySize`, `timeout` etc. use the top level `provider` which will override the functions configuration. For example, to change the memorySize to 512MB:

classes/NextPage.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const path = require("path");
22
const merge = require("lodash.merge");
3+
const clone = require("lodash.clonedeep");
34
const toPosix = require("../utils/pathToPosix");
45
const PluginBuildDir = require("./PluginBuildDir");
56

@@ -85,10 +86,24 @@ class NextPage {
8586
merge(configuration, this.serverlessFunctionOverrides);
8687
}
8788

89+
const httpHeadEvents = this.getMatchingHttpHeadEvents(
90+
configuration.events.filter(e => e.http.method === "get")
91+
);
92+
93+
configuration.events = configuration.events.concat(httpHeadEvents);
94+
8895
return {
8996
[this.functionName]: configuration
9097
};
9198
}
99+
100+
getMatchingHttpHeadEvents(httpGetEvents) {
101+
return httpGetEvents.map(e => {
102+
const headEvent = clone(e);
103+
headEvent.http.method = "head";
104+
return headEvent;
105+
});
106+
}
92107
}
93108

94109
module.exports = NextPage;

classes/__tests__/NextPage.test.js

Lines changed: 121 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ describe("NextPage", () => {
2222
});
2323

2424
describe("#serverlessFunction", () => {
25-
it("should return function http event path /", () => {
25+
it("should have http GET event with path /", () => {
2626
const { events } = page.serverlessFunction.indexPage;
2727

28-
expect(events).toHaveLength(1);
29-
3028
const httpEvent = events[0].http;
29+
expect(httpEvent.method).toEqual("get");
30+
expect(httpEvent.path).toEqual("/");
31+
});
32+
33+
it("should have http HEAD event with path /", () => {
34+
const { events } = page.serverlessFunction.indexPage;
35+
36+
const httpEvent = events[1].http;
37+
expect(httpEvent.method).toEqual("head");
3138
expect(httpEvent.path).toEqual("/");
3239
});
3340
});
@@ -47,13 +54,27 @@ describe("NextPage", () => {
4754
expect(page.serverlessFunction.notFoundErrorPage).toBeDefined();
4855
});
4956

50-
it("should return function http event path /{proxy+}", () => {
57+
it("should return two events", () => {
58+
const { events } = page.serverlessFunction.notFoundErrorPage;
59+
expect(events).toHaveLength(2);
60+
});
61+
62+
it("should return http event path /{proxy+} with GET method", () => {
5163
const { events } = page.serverlessFunction.notFoundErrorPage;
5264

53-
expect(events).toHaveLength(1);
65+
const httpGet = events[0].http;
5466

55-
const httpEvent = events[0].http;
56-
expect(httpEvent.path).toEqual("/{proxy+}");
67+
expect(httpGet.path).toEqual("/{proxy+}");
68+
expect(httpGet.method).toEqual("get");
69+
});
70+
71+
it("should return http event path /{proxy+} with HEAD method", () => {
72+
const { events } = page.serverlessFunction.notFoundErrorPage;
73+
74+
const httpHead = events[1].http;
75+
76+
expect(httpHead.path).toEqual("/{proxy+}");
77+
expect(httpHead.method).toEqual("head");
5778
});
5879
});
5980
});
@@ -71,12 +92,15 @@ describe("NextPage", () => {
7192
it("should have URI path matching subdirectories", () => {
7293
const { events } = page.serverlessFunction.fridgesPage;
7394

74-
expect(events).toHaveLength(1);
95+
expect(events).toHaveLength(2);
7596

76-
const httpEvent = events[0].http;
97+
const httpGet = events[0].http;
98+
const httpHead = events[1].http;
7799

78-
expect(httpEvent.path).toEqual("categories/fridge/fridges");
79-
expect(httpEvent.method).toEqual("get");
100+
expect(httpGet.path).toEqual("categories/fridge/fridges");
101+
expect(httpGet.method).toEqual("get");
102+
expect(httpHead.path).toEqual("categories/fridge/fridges");
103+
expect(httpHead.method).toEqual("head");
80104
});
81105
});
82106
});
@@ -167,54 +191,105 @@ describe("NextPage", () => {
167191
expect(handler).toEqual(`${buildDir}/admin.render`);
168192
});
169193

170-
it("should return function http event", () => {
194+
it("should return 2 http events", () => {
171195
const { events } = page.serverlessFunction.adminPage;
196+
expect(events).toHaveLength(2);
197+
});
172198

173-
expect(events).toHaveLength(1);
199+
it("should return function http GET event", () => {
200+
const { events } = page.serverlessFunction.adminPage;
174201

175202
const httpEvent = events[0].http;
176203

177204
expect(httpEvent.path).toEqual("admin");
178205
expect(httpEvent.method).toEqual("get");
179206
});
180207

181-
it("should override serverlessFunction with provided pageConfig", () => {
182-
const serverlessFunctionOverrides = { foo: "bar" };
183-
184-
const pageWithCustomConfig = new NextPage(
185-
pagePath,
186-
serverlessFunctionOverrides
187-
);
188-
189-
expect(pageWithCustomConfig.serverlessFunction.adminPage.foo).toBe(
190-
"bar"
191-
);
192-
});
193-
194-
it("should NOT change handler with provided pageConfig", () => {
195-
const serverlessFunctionOverrides = { handler: "invalid/handler" };
208+
it("should return function http HEAD event", () => {
209+
const { events } = page.serverlessFunction.adminPage;
196210

197-
const pageWithCustomConfig = new NextPage(
198-
pagePath,
199-
serverlessFunctionOverrides
200-
);
211+
const httpEvent = events[1].http;
201212

202-
expect(pageWithCustomConfig.serverlessFunction.adminPage.handler).toBe(
203-
pageWithCustomConfig.pageHandler
204-
);
213+
expect(httpEvent.path).toEqual("admin");
214+
expect(httpEvent.method).toEqual("head");
205215
});
206216

207-
it("should NOT change runtime with provided pageConfig", () => {
208-
const serverlessFunctionOverrides = { runtime: "python2.7" };
209-
210-
const pageWithCustomConfig = new NextPage(
211-
pagePath,
212-
serverlessFunctionOverrides
213-
);
214-
215-
expect(pageWithCustomConfig.serverlessFunction.adminPage.runtime).toBe(
216-
undefined
217-
);
217+
describe("When pageConfig override is provided", () => {
218+
it("should create identical HEAD route for custom GET route", () => {
219+
const serverlessFunctionOverrides = {
220+
events: [
221+
{
222+
http: {
223+
path: "admin/{id}",
224+
request: {
225+
parameters: {
226+
id: true
227+
}
228+
}
229+
}
230+
}
231+
]
232+
};
233+
234+
const pageWithCustomConfig = new NextPage(
235+
pagePath,
236+
serverlessFunctionOverrides
237+
);
238+
239+
const { events } = pageWithCustomConfig.serverlessFunction.adminPage;
240+
expect(events).toHaveLength(2);
241+
242+
const httpGet = events[0].http;
243+
const httpHead = events[1].http;
244+
245+
expect(httpGet.method).toBe("get");
246+
expect(httpHead.method).toBe("head");
247+
248+
expect(httpGet.path).toBe("admin/{id}");
249+
expect(httpHead.path).toBe("admin/{id}");
250+
251+
expect(httpGet.request.parameters.id).toBe(true);
252+
expect(httpHead.request.parameters.id).toBe(true);
253+
});
254+
255+
it("should override serverlessFunction with provided pageConfig", () => {
256+
const serverlessFunctionOverrides = { foo: "bar" };
257+
258+
const pageWithCustomConfig = new NextPage(
259+
pagePath,
260+
serverlessFunctionOverrides
261+
);
262+
263+
expect(pageWithCustomConfig.serverlessFunction.adminPage.foo).toBe(
264+
"bar"
265+
);
266+
});
267+
268+
it("should NOT change handler with provided pageConfig", () => {
269+
const serverlessFunctionOverrides = { handler: "invalid/handler" };
270+
271+
const pageWithCustomConfig = new NextPage(
272+
pagePath,
273+
serverlessFunctionOverrides
274+
);
275+
276+
expect(
277+
pageWithCustomConfig.serverlessFunction.adminPage.handler
278+
).toBe(pageWithCustomConfig.pageHandler);
279+
});
280+
281+
it("should NOT change runtime with provided pageConfig", () => {
282+
const serverlessFunctionOverrides = { runtime: "python2.7" };
283+
284+
const pageWithCustomConfig = new NextPage(
285+
pagePath,
286+
serverlessFunctionOverrides
287+
);
288+
289+
expect(
290+
pageWithCustomConfig.serverlessFunction.adminPage.runtime
291+
).toBe(undefined);
292+
});
218293
});
219294
});
220295
});

integration/__tests__/package.test.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ describe.each`
113113

114114
describe("API gateway", () => {
115115
let apiGWPageResources;
116+
let apiGWGETMethodResources;
117+
let apiGWHEADMethodResources;
116118

117119
beforeAll(() => {
118120
apiGWPageResources = {
@@ -122,6 +124,22 @@ describe.each`
122124
blog: resources.ApiGatewayResourceBlog,
123125
fridges: resources.ApiGatewayResourceCategoriesFridgeFridges
124126
};
127+
128+
apiGWGETMethodResources = {
129+
home: resources.ApiGatewayMethodHomeGet,
130+
about: resources.ApiGatewayMethodAboutGet,
131+
post: resources.ApiGatewayMethodPostsIdVarGet,
132+
blog: resources.ApiGatewayMethodBlogGet,
133+
fridges: resources.ApiGatewayMethodCategoriesFridgeFridgesGet
134+
};
135+
136+
apiGWHEADMethodResources = {
137+
home: resources.ApiGatewayMethodHomeHead,
138+
about: resources.ApiGatewayMethodAboutHead,
139+
post: resources.ApiGatewayMethodPostsIdVarHead,
140+
blog: resources.ApiGatewayMethodBlogHead,
141+
fridges: resources.ApiGatewayMethodCategoriesFridgeFridgesHead
142+
};
125143
});
126144

127145
it.each`
@@ -153,6 +171,36 @@ describe.each`
153171
);
154172
});
155173

174+
it.each`
175+
pageName | uri
176+
${"home"} | ${"home"}
177+
${"about"} | ${"about"}
178+
${"blog"} | ${"blog"}
179+
${"fridges"} | ${"fridges"}
180+
`("page $pageName should have GET and HEAD methods", ({ pageName }) => {
181+
expect(apiGWPageResources[pageName].Properties.PathPart).toEqual(
182+
pageName
183+
);
184+
});
185+
186+
it.each`
187+
pageName | uri
188+
${"home"} | ${"home"}
189+
${"about"} | ${"about"}
190+
${"blog"} | ${"blog"}
191+
${"fridges"} | ${"fridges"}
192+
`(
193+
"page $pageName should have a GET and HEAD methods",
194+
({ pageName }) => {
195+
expect(
196+
apiGWGETMethodResources[pageName].Properties.HttpMethod
197+
).toEqual("GET");
198+
expect(
199+
apiGWHEADMethodResources[pageName].Properties.HttpMethod
200+
).toEqual("HEAD");
201+
}
202+
);
203+
156204
it("post page should have custom path and id parameter", () => {
157205
expect(apiGWPageResources["post"].Properties.PathPart).toEqual(
158206
"posts"

0 commit comments

Comments
 (0)