Skip to content

Commit

Permalink
Merge pull request #73 from bouwe77/headers-in-requestInterceptor
Browse files Browse the repository at this point in the history
Add headers to `requestInterceptor` callbacks
  • Loading branch information
bouwe77 authored Aug 16, 2024
2 parents 6773fc4 + d2e0e34 commit 38d6f3b
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 57 deletions.
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,19 +265,19 @@ It allows you to implement your own validation, or even change the request body.
```js
const config = {
requestInterceptor: {
get: ({ resource, id }) => {
get: ({ headers, resource, id }) => {
//...
},
post: ({ resource, body }) => {
post: ({ headers, resource, body }) => {
// Validate, or even change the request body
},
put: ({ resource, id, body }) => {
put: ({ headers, resource, id, body }) => {
// Validate, or even change the request body
},
patch: ({ resource, id, body }) => {
patch: ({ headers, resource, id, body }) => {
// Validate, or even change the request body
},
delete: ({ resource, id }) => {
delete: ({ headers, resource, id }) => {
//...
},
},
Expand All @@ -288,7 +288,9 @@ const server = create(config)

The `requestInterceptor` is an object with fields for each of the HTTP methods you might want to intercept, and the callback function you want Temba to call, before processing the request, i.e. going to the database.

Each callback function receives an object containing the `resource` (e.g. `"movies"`). Depending on the HTTP method, also the `id` from the URL, and the request `body` are provided. `body` is a JSON object of the request body.
Each callback function receives an object containing the request headers and the `resource` (e.g. `"movies"`). Depending on the HTTP method, also the `id` from the URL, and the request `body` are provided. `body` is a JSON object of the request body.

> Request headers are not used by Temba internally when processing requests, so they are only passed into the `requestInterceptor` callback so you can do your own custom header validation.
Your callback function can return the following things:

Expand All @@ -301,7 +303,7 @@ Example:
```js
const config = {
requestInterceptor: {
post: ({ resource, body }) => {
post: ({ headers, resource, body }) => {
// Add a genre to Star Trek films:
if (resource === 'movies' && body.title.startsWith('Star Trek'))
return { ...body, genre: 'Science Fiction' }
Expand Down Expand Up @@ -457,19 +459,19 @@ const config = {
etags: true,
port: 4321,
requestInterceptor: {
get: ({ resource, id }) => {
get: ({ headers, resource, id }) => {
//...
},
post: ({ resource, body }) => {
post: ({ headers, resource, body }) => {
// Validate, or even change the request body
},
put: ({ resource, id, body }) => {
put: ({ headers, resource, id, body }) => {
// Validate, or even change the request body
},
patch: ({ resource, id, body }) => {
patch: ({ headers, resource, id, body }) => {
// Validate, or even change the request body
},
delete: ({ resource, id }) => {
delete: ({ headers, resource, id }) => {
//...
},
},
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "temba",
"version": "0.33.0",
"version": "0.34.0",
"description": "Get a simple REST API with zero coding in less than 30 seconds (seriously).",
"type": "module",
"main": "dist/src/index.js",
Expand Down
4 changes: 2 additions & 2 deletions src/requestHandlers/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ export const createDeleteRoutes = (
) => {
const handleDelete = async (req: DeleteRequest) => {
try {
const { resource, id } = req
const { headers, resource, id } = req

if (requestInterceptor?.delete) {
try {
interceptDeleteRequest(requestInterceptor.delete, resource, id)
interceptDeleteRequest(requestInterceptor.delete, headers, resource, id)
} catch (error: unknown) {
return {
status: error instanceof TembaError ? error.statusCode : 500,
Expand Down
4 changes: 2 additions & 2 deletions src/requestHandlers/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export const createGetRoutes = (

const handleGet = async (req: GetRequest) => {
try {
const { resource, id } = req
const { headers, resource, id } = req

if (!req.isHeadRequest && requestInterceptor?.get) {
try {
interceptGetRequest(requestInterceptor.get, resource, id)
interceptGetRequest(requestInterceptor.get, headers, resource, id)
} catch (error: unknown) {
return {
status: error instanceof TembaError ? error.statusCode : 500,
Expand Down
4 changes: 2 additions & 2 deletions src/requestHandlers/patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const createPatchRoutes = (
) => {
const handlePatch = async (req: PatchRequest) => {
try {
const { body, resource, id } = req
const { headers, body, resource, id } = req

const validationResult = validate(body, schemas?.[resource])
if (validationResult.isValid === false) {
Expand All @@ -27,7 +27,7 @@ export const createPatchRoutes = (
let body2 = body
if (requestInterceptor?.patch) {
try {
body2 = interceptPatchRequest(requestInterceptor.patch, resource, id, body)
body2 = interceptPatchRequest(requestInterceptor.patch, headers, resource, id, body)
} catch (error: unknown) {
return {
status: error instanceof TembaError ? error.statusCode : 500,
Expand Down
4 changes: 2 additions & 2 deletions src/requestHandlers/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const createPostRoutes = (
) => {
const handlePost = async (req: PostRequest) => {
try {
const { body, protocol, host, resource } = req
const { headers, body, protocol, host, resource } = req

const validationResult = validate(body, schemas[resource])
if (validationResult.isValid === false) {
Expand All @@ -26,7 +26,7 @@ export const createPostRoutes = (
let body2 = body
if (requestInterceptor?.post) {
try {
body2 = interceptPostRequest(requestInterceptor.post, resource, body)
body2 = interceptPostRequest(requestInterceptor.post, headers, resource, body)
} catch (error: unknown) {
return {
status: error instanceof TembaError ? error.statusCode : 500,
Expand Down
4 changes: 2 additions & 2 deletions src/requestHandlers/put.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const createPutRoutes = (
) => {
const handlePut = async (req: PutRequest) => {
try {
const { body, resource, id } = req
const { headers, body, resource, id } = req

const validationResult = validate(body, schemas?.[resource])
if (validationResult.isValid === false) {
Expand All @@ -27,7 +27,7 @@ export const createPutRoutes = (
let body2 = body
if (requestInterceptor?.put) {
try {
body2 = interceptPutRequest(requestInterceptor.put, resource, id, body)
body2 = interceptPutRequest(requestInterceptor.put, headers, resource, id, body)
} catch (error: unknown) {
return {
status: error instanceof TembaError ? error.statusCode : 500,
Expand Down
4 changes: 4 additions & 0 deletions src/requestHandlers/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { IncomingHttpHeaders } from 'http'

export type UrlInfo = {
resource: string | null
id: string | null
Expand All @@ -10,6 +12,7 @@ export type RequestInfo = {
host: string | null
protocol: string | null
method: string
headers: IncomingHttpHeaders
etag: string | null
}

Expand All @@ -19,6 +22,7 @@ export type ErrorResponse = {
}

export type TembaRequest = {
headers: IncomingHttpHeaders
resource: string
}

Expand Down
14 changes: 10 additions & 4 deletions src/requestInterceptor/interceptRequest.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { IncomingHttpHeaders } from 'http'

import type {
InterceptedDeleteRequest,
InterceptedGetRequest,
Expand All @@ -8,39 +10,43 @@ import type {

export const interceptGetRequest = (
intercept: InterceptedGetRequest,
headers: IncomingHttpHeaders,
resource: string,
id: string | null,
) => {
intercept({ resource, id })
intercept({ headers, resource, id })
}

export const interceptPostRequest = (
intercept: InterceptedPostRequest,
headers: IncomingHttpHeaders,
resource: string,
body: unknown,
) => {
const intercepted = intercept({ resource, body })
const intercepted = intercept({ headers, resource, body })
return interceptRequest(intercepted, body)
}

export const interceptPutRequest = (
intercept: InterceptedPutRequest,
headers: IncomingHttpHeaders,
resource: string,
id: string,
body: unknown,
) => {
const intercepted = intercept({ resource, id, body })
const intercepted = intercept({ headers, resource, id, body })
return interceptRequest(intercepted, body)
}

export const interceptPatchRequest = interceptPutRequest

export const interceptDeleteRequest = (
intercept: InterceptedDeleteRequest,
headers: IncomingHttpHeaders,
resource: string,
id: string | null,
) => {
intercept({ resource, id })
intercept({ headers, resource, id })
}

const interceptRequest = (intercepted: InterceptedReturnValue, body: unknown) => {
Expand Down
3 changes: 3 additions & 0 deletions src/requestInterceptor/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { IncomingHttpHeaders } from 'http'

type InterceptedResource = {
headers: IncomingHttpHeaders
resource: string
}

Expand Down
5 changes: 5 additions & 0 deletions src/resourceRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const validateIdInRequestBodyNotAllowed = (requestInfo: RequestInfo) => {

const convertToGetRequest = (requestInfo: RequestInfo) => {
return {
headers: requestInfo.headers,
id: requestInfo.id,
resource: requestInfo.resource,
isHeadRequest: requestInfo.method.toUpperCase() === 'HEAD',
Expand All @@ -54,6 +55,7 @@ const convertToGetRequest = (requestInfo: RequestInfo) => {

const convertToPostRequest = (requestInfo: RequestInfo) => {
return {
headers: requestInfo.headers,
resource: requestInfo.resource,
body: requestInfo.body ?? {},
protocol: requestInfo.protocol,
Expand All @@ -63,6 +65,7 @@ const convertToPostRequest = (requestInfo: RequestInfo) => {

const convertToPutRequest = (requestInfo: RequestInfo) => {
return {
headers: requestInfo.headers,
id: requestInfo.id!,
resource: requestInfo.resource,
body: requestInfo.body ?? {},
Expand All @@ -74,6 +77,7 @@ const convertToPatchRequest = convertToPutRequest

const convertToDeleteRequest = (requestInfo: RequestInfo) => {
return {
headers: requestInfo.headers,
id: requestInfo.id,
resource: requestInfo.resource,
etag: requestInfo.etag ?? null,
Expand Down Expand Up @@ -108,6 +112,7 @@ export const createResourceRouter = (
host,
protocol,
method: req.method,
headers: req.headers,
etag,
} satisfies RequestInfo
}
Expand Down
Loading

0 comments on commit 38d6f3b

Please sign in to comment.