Skip to content

Commit 135c2dd

Browse files
committed
PoC: move onRequest from prehandler to get and post handlers
1 parent ac41bb2 commit 135c2dd

7 files changed

Lines changed: 166 additions & 136 deletions

File tree

docs/PLUGIN_OPTIONS.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,8 @@ If provided, the `onRequest` plugin option will be invoked on each request to an
8484
```ts
8585
export type OnRequestCallback = (
8686
request: AnyFormRequest,
87-
params: FormParams,
88-
definition: FormDefinition,
89-
metadata: FormMetadata
87+
h: ResponseToolkit,
88+
context: FormContext
9089
) => void
9190
```
9291
@@ -96,12 +95,13 @@ Here's an example of how it could be used to secure access to forms:
9695
await server.register({
9796
plugin,
9897
options: {
99-
onRequest: (request , params, definition, metadata) => {
100-
const { auth } = request
98+
onRequest: (request , h, context) => {
99+
const redirectUrl = mapStatusToUrl(applicationStatus, grantCode)
100+
if (request.path === redirectUrl) {
101+
return h.continue
102+
}
101103

102-
if (!auth.isAuthenticated) {
103-
throw Boom.unauthorized()
104-
}
104+
return h.redirect(redirectUrl).takeover()
105105
}
106106
}
107107
})

src/server/plugins/engine/plugin.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ export const plugin = {
3434
saveAndExit,
3535
nunjucks: nunjucksOptions,
3636
viewContext,
37-
preparePageEventRequestOptions
37+
preparePageEventRequestOptions,
38+
onRequest
3839
} = options
3940

4041
const cacheService =
@@ -83,7 +84,8 @@ export const plugin = {
8384
...getQuestionRoutes(
8485
getRouteOptions,
8586
postRouteOptions,
86-
preparePageEventRequestOptions
87+
preparePageEventRequestOptions,
88+
onRequest
8789
),
8890
...getRepeaterSummaryRoutes(getRouteOptions, postRouteOptions),
8991
...getRepeaterItemDeleteRoutes(getRouteOptions, postRouteOptions),

src/server/plugins/engine/routes/index.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import * as defaultServices from '~/src/server/plugins/engine/services/index.js'
2323
import {
2424
type AnyFormRequest,
2525
type FormContext,
26+
type OnRequestCallback,
2627
type PluginOptions
2728
} from '~/src/server/plugins/engine/types.js'
2829
import {
@@ -33,6 +34,7 @@ import {
3334
export async function redirectOrMakeHandler(
3435
request: AnyFormRequest,
3536
h: FormResponseToolkit,
37+
onRequest: OnRequestCallback | undefined,
3638
makeHandler: (
3739
page: PageControllerClass,
3840
context: FormContext
@@ -69,6 +71,14 @@ export async function redirectOrMakeHandler(
6971
const relevantPath = page.getRelevantPath(request, context)
7072
const summaryPath = page.getSummaryPath()
7173

74+
// Call the onRequest callback if it has been supplied
75+
if (onRequest) {
76+
const result = await onRequest(request, h as ResponseToolkit, context)
77+
if (result) {
78+
return result // no need to check for `isTakeover`, TypeScript is happy
79+
}
80+
}
81+
7282
// Return handler for relevant pages or preview URL direct access
7383
if (relevantPath.startsWith(page.path) || context.isForceAccess) {
7484
return makeHandler(page, context)
@@ -89,7 +99,7 @@ export function makeLoadFormPreHandler(server: Server, options: PluginOptions) {
8999
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- hapi types are wrong
90100
const prefix = server.realm.modifiers.route.prefix ?? ''
91101

92-
const { services = defaultServices, controllers, onRequest } = options
102+
const { services = defaultServices, controllers } = options
93103

94104
const { formsService } = services
95105

@@ -166,11 +176,6 @@ export function makeLoadFormPreHandler(server: Server, options: PluginOptions) {
166176
server.app.models.set(key, item)
167177
}
168178

169-
// Call the onRequest callback if it has been supplied
170-
if (onRequest) {
171-
onRequest(request, params, item.model.def, metadata)
172-
}
173-
174179
// Assign the model to the request data
175180
// for use in the downstream handler
176181
request.app.model = item.model

src/server/plugins/engine/routes/questions.ts

Lines changed: 71 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
import {
2727
type AnyFormRequest,
2828
type FormContext,
29+
type OnRequestCallback,
2930
type PreparePageEventRequestOptions
3031
} from '~/src/server/plugins/engine/types.js'
3132
import {
@@ -74,7 +75,8 @@ async function handleHttpEvent(
7475
}
7576

7677
export function makeGetHandler(
77-
preparePageEventRequestOptions?: PreparePageEventRequestOptions
78+
preparePageEventRequestOptions?: PreparePageEventRequestOptions,
79+
onRequest?: OnRequestCallback
7880
) {
7981
return function getHandler(request: FormRequest, h: FormResponseToolkit) {
8082
const { params } = request
@@ -83,75 +85,86 @@ export function makeGetHandler(
8385
return dispatchHandler(request, h)
8486
}
8587

86-
return redirectOrMakeHandler(request, h, async (page, context) => {
87-
// Check for a page onLoad HTTP event and if one exists,
88-
// call it and assign the response to the context data
89-
const { events } = page
90-
const { model } = request.app
88+
return redirectOrMakeHandler(
89+
request,
90+
h,
91+
onRequest,
92+
async (page, context) => {
93+
// Check for a page onLoad HTTP event and if one exists,
94+
// call it and assign the response to the context data
95+
const { events } = page
96+
const { model } = request.app
9197

92-
if (!model) {
93-
throw Boom.notFound(`No model found for /${params.path}`)
94-
}
98+
if (!model) {
99+
throw Boom.notFound(`No model found for /${params.path}`)
100+
}
95101

96-
if (events?.onLoad && events.onLoad.type === 'http') {
97-
await handleHttpEvent(
98-
request,
99-
page,
100-
context,
101-
events.onLoad,
102-
model,
103-
preparePageEventRequestOptions
104-
)
105-
}
102+
if (events?.onLoad && events.onLoad.type === 'http') {
103+
await handleHttpEvent(
104+
request,
105+
page,
106+
context,
107+
events.onLoad,
108+
model,
109+
preparePageEventRequestOptions
110+
)
111+
}
106112

107-
return page.makeGetRouteHandler()(request, context, h)
108-
})
113+
return page.makeGetRouteHandler()(request, context, h)
114+
}
115+
)
109116
}
110117
}
111118

112119
export function makePostHandler(
113-
preparePageEventRequestOptions?: PreparePageEventRequestOptions
120+
preparePageEventRequestOptions?: PreparePageEventRequestOptions,
121+
onRequest?: OnRequestCallback
114122
) {
115123
return function postHandler(
116124
request: FormRequestPayload,
117125
h: FormResponseToolkit
118126
) {
119127
const { query } = request
120128

121-
return redirectOrMakeHandler(request, h, async (page, context) => {
122-
const { pageDef } = page
123-
const { isForceAccess } = context
124-
const { model } = request.app
125-
const { events } = page
129+
return redirectOrMakeHandler(
130+
request,
131+
h,
132+
onRequest,
133+
async (page, context) => {
134+
const { pageDef } = page
135+
const { isForceAccess } = context
136+
const { model } = request.app
137+
const { events } = page
126138

127-
// Redirect to GET for preview URL direct access
128-
if (isForceAccess && !hasFormComponents(pageDef)) {
129-
return proceed(request, h, redirectPath(page.href, query))
130-
}
139+
// Redirect to GET for preview URL direct access
140+
if (isForceAccess && !hasFormComponents(pageDef)) {
141+
return proceed(request, h, redirectPath(page.href, query))
142+
}
131143

132-
if (!model) {
133-
throw Boom.notFound(`No model found for /${request.params.path}`)
134-
}
144+
if (!model) {
145+
throw Boom.notFound(`No model found for /${request.params.path}`)
146+
}
135147

136-
const response = await page.makePostRouteHandler()(request, context, h)
148+
const response = await page.makePostRouteHandler()(request, context, h)
137149

138-
if (
139-
events?.onSave &&
140-
events.onSave.type === 'http' &&
141-
isSuccessful(response)
142-
) {
143-
await handleHttpEvent(
144-
request,
145-
page,
146-
context,
147-
events.onSave,
148-
model,
149-
preparePageEventRequestOptions
150-
)
151-
}
150+
if (
151+
events?.onSave &&
152+
events.onSave.type === 'http' &&
153+
isSuccessful(response)
154+
) {
155+
await handleHttpEvent(
156+
request,
157+
page,
158+
context,
159+
events.onSave,
160+
model,
161+
preparePageEventRequestOptions
162+
)
163+
}
152164

153-
return response
154-
})
165+
return response
166+
}
167+
)
155168
}
156169
}
157170

@@ -164,13 +177,14 @@ function isSuccessful(response: ResponseObject): boolean {
164177
export function getRoutes(
165178
getRouteOptions: RouteOptions<FormRequestRefs>,
166179
postRouteOptions: RouteOptions<FormRequestPayloadRefs>,
167-
preparePageEventRequestOptions?: PreparePageEventRequestOptions
180+
preparePageEventRequestOptions?: PreparePageEventRequestOptions,
181+
onRequest?: OnRequestCallback
168182
): (ServerRoute<FormRequestRefs> | ServerRoute<FormRequestPayloadRefs>)[] {
169183
return [
170184
{
171185
method: 'get',
172186
path: '/{slug}',
173-
handler: makeGetHandler(preparePageEventRequestOptions),
187+
handler: makeGetHandler(preparePageEventRequestOptions, onRequest),
174188
options: {
175189
...getRouteOptions,
176190
validate: {
@@ -197,7 +211,7 @@ export function getRoutes(
197211
{
198212
method: 'get',
199213
path: '/{slug}/{path}/{itemId?}',
200-
handler: makeGetHandler(preparePageEventRequestOptions),
214+
handler: makeGetHandler(preparePageEventRequestOptions, onRequest),
201215
options: {
202216
...getRouteOptions,
203217
validate: {
@@ -212,7 +226,7 @@ export function getRoutes(
212226
{
213227
method: 'get',
214228
path: '/preview/{state}/{slug}/{path}/{itemId?}',
215-
handler: makeGetHandler(preparePageEventRequestOptions),
229+
handler: makeGetHandler(preparePageEventRequestOptions, onRequest),
216230
options: {
217231
...getRouteOptions,
218232
validate: {
@@ -228,7 +242,7 @@ export function getRoutes(
228242
{
229243
method: 'post',
230244
path: '/{slug}/{path}/{itemId?}',
231-
handler: makePostHandler(preparePageEventRequestOptions),
245+
handler: makePostHandler(preparePageEventRequestOptions, onRequest),
232246
options: {
233247
...postRouteOptions,
234248
validate: {
@@ -250,7 +264,7 @@ export function getRoutes(
250264
{
251265
method: 'post',
252266
path: '/preview/{state}/{slug}/{path}/{itemId?}',
253-
handler: makePostHandler(preparePageEventRequestOptions),
267+
handler: makePostHandler(preparePageEventRequestOptions, onRequest),
254268
options: {
255269
...postRouteOptions,
256270
validate: {

0 commit comments

Comments
 (0)