Skip to content

Commit

Permalink
feat: add routeSchema and routeConfig + switching context handling (#…
Browse files Browse the repository at this point in the history
…4216)

* bumped v5.0.0-dev

Signed-off-by: Matteo Collina <hello@matteocollina.com>

* feat: initial implementation of context handling switch

* refactor: hide context for reply/request

* fix: remove trailling space

* tests: adjust tests based on new way of handling context

* refactor: rename route context symbol

* feat: expose route context through request object

* chore: add temporary context

* refactor: reverting log-level

* refactor: export config/schema into its own naming

* docs: update docs reflecting changes to request/reply

* tests: extend coverage

* refactor: initial cleanup

* tests: remove todo and adjust config test

* chore: emit warning on access to Request#context

* refactor: apply review

* docs: restore context docs

Signed-off-by: Matteo Collina <hello@matteocollina.com>
Co-authored-by: Matteo Collina <hello@matteocollina.com>
Co-authored-by: KaKa <kaka@kakawebsitedemo.com>
  • Loading branch information
3 people committed Sep 27, 2022
1 parent ca1aa69 commit 7ffefaf
Show file tree
Hide file tree
Showing 21 changed files with 283 additions and 210 deletions.
10 changes: 5 additions & 5 deletions docs/Reference/Reply.md
Expand Up @@ -7,22 +7,22 @@
- [.statusCode](#statuscode)
- [.server](#server)
- [.header(key, value)](#headerkey-value)
- [set-cookie](#set-cookie)
- [.headers(object)](#headersobject)
- [.getHeader(key)](#getheaderkey)
- [.getHeaders()](#getheaders)
- [set-cookie](#set-cookie)
- [.removeHeader(key)](#removeheaderkey)
- [.hasHeader(key)](#hasheaderkey)
- [.trailer(key, function)](#trailerkey-function)
- [.hasTrailer(key)](#hastrailerkey)
- [.removeTrailer(key)](#removetrailerkey)
- [.redirect([code,] dest)](#redirectcode--dest)
- [.redirect([code ,] dest)](#redirectcode--dest)
- [.callNotFound()](#callnotfound)
- [.getResponseTime()](#getresponsetime)
- [.type(contentType)](#typecontenttype)
- [.getSerializationFunction(schema | httpStatus)](#getserializationfunction)
- [.compileSerializationSchema(schema, httpStatus)](#compileserializationschema)
- [.serializeInput(data, [schema | httpStatus], [httpStatus])](#serializeinput)
- [.getSerializationFunction(schema | httpStatus)](#getserializationfunctionschema--httpstatus)
- [.compileSerializationSchema(schema, httpStatus)](#compileserializationschemaschema-httpstatus)
- [.serializeInput(data, [schema | httpStatus], [httpStatus])](#serializeinputdata-schema--httpstatus-httpstatus)
- [.serializer(func)](#serializerfunc)
- [.raw](#raw)
- [.sent](#sent)
Expand Down
10 changes: 7 additions & 3 deletions docs/Reference/Request.md
Expand Up @@ -35,6 +35,13 @@ Request is a core Fastify object containing the following fields:
- `connection` - Deprecated, use `socket` instead. The underlying connection of
the incoming request.
- `socket` - the underlying connection of the incoming request
- `context` - A Fastify internal object. You should not use it directly or
modify it. It is useful to access one special key:
- `context.config` - The route [`config`](./Routes.md#routes-config) object.
- `routeSchema` - the scheme definition set for the router that is
handling the request
- `routeConfig` - The route [`config`](./Routes.md#routes-config)
object.
- [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
Returns a validation function for the specified schema or http part,
if any of either are set or cached.
Expand All @@ -48,9 +55,6 @@ Request is a core Fastify object containing the following fields:
schema and returns the serialized payload. If the optional
`httpPart` is provided, the function will use the serializer
function given for that HTTP Status Code. Defaults to `null`.
- `context` - A Fastify internal object. You should not use it directly or
modify it. It is useful to access one special key:
- `context.config` - The route [`config`](./Routes.md#routes-config) object.

### Headers

Expand Down
5 changes: 3 additions & 2 deletions lib/contentTypeParser.js
Expand Up @@ -15,7 +15,8 @@ const {
kRequestPayloadStream,
kState,
kTestInternals,
kReplyIsError
kReplyIsError,
kRouteContext
} = require('./symbols')

const {
Expand Down Expand Up @@ -158,7 +159,7 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
rawBody(
request,
reply,
reply.context._parserOptions,
reply[kRouteContext]._parserOptions,
parser,
done
)
Expand Down
28 changes: 26 additions & 2 deletions lib/context.js
Expand Up @@ -12,7 +12,8 @@ const {
kContentTypeParser,
kRouteByFastify,
kRequestValidateWeakMap,
kReplySerializeWeakMap
kReplySerializeWeakMap,
kPublicRouteContext
} = require('./symbols.js')

// Object that holds the context of every request
Expand Down Expand Up @@ -56,17 +57,40 @@ function Context ({
this[kFourOhFourContext] = null
this.attachValidation = attachValidation
this[kReplySerializerDefault] = replySerializer
this.schemaErrorFormatter = schemaErrorFormatter || server[kSchemaErrorFormatter] || defaultSchemaErrorFormatter
this.schemaErrorFormatter =
schemaErrorFormatter ||
server[kSchemaErrorFormatter] ||
defaultSchemaErrorFormatter
this[kRouteByFastify] = isFastify

this[kRequestValidateWeakMap] = null
this[kReplySerializeWeakMap] = null
this.validatorCompiler = validatorCompiler || null
this.serializerCompiler = serializerCompiler || null

// Route + Userland configurations for the route
this[kPublicRouteContext] = getPublicRouteContext(this)

this.server = server
}

function getPublicRouteContext (context) {
return Object.create(null, {
schema: {
enumerable: true,
get () {
return context.schema
}
},
config: {
enumerable: true,
get () {
return context.config
}
}
})
}

function defaultSchemaErrorFormatter (errors, dataVar) {
let text = ''
const separator = ', '
Expand Down
10 changes: 7 additions & 3 deletions lib/error-handler.js
Expand Up @@ -3,7 +3,11 @@
const statusCodes = require('http').STATUS_CODES
const wrapThenable = require('./wrapThenable')
const {
kReplyHeaders, kReplyNextErrorHandler, kReplyIsRunningOnErrorHook, kReplyHasStatusCode
kReplyHeaders,
kReplyNextErrorHandler,
kReplyIsRunningOnErrorHook,
kReplyHasStatusCode,
kRouteContext
} = require('./symbols.js')

const {
Expand All @@ -24,7 +28,7 @@ const rootErrorHandler = {
function handleError (reply, error, cb) {
reply[kReplyIsRunningOnErrorHook] = false

const context = reply.context
const context = reply[kRouteContext]
if (reply[kReplyNextErrorHandler] === false) {
fallbackErrorHandler(error, reply, function (reply, payload) {
try {
Expand Down Expand Up @@ -90,7 +94,7 @@ function fallbackErrorHandler (error, reply, cb) {
const statusCode = reply.statusCode
let payload
try {
const serializerFn = getSchemaSerializer(reply.context, statusCode)
const serializerFn = getSchemaSerializer(reply[kRouteContext], statusCode)
payload = (serializerFn === false)
? serializeError({
error: statusCodes[statusCode + ''],
Expand Down
24 changes: 13 additions & 11 deletions lib/handleRequest.js
Expand Up @@ -4,7 +4,8 @@ const { validate: validateSchema } = require('./validation')
const { hookRunner, hookIterator } = require('./hooks')
const wrapThenable = require('./wrapThenable')
const {
kReplyIsError
kReplyIsError,
kRouteContext
} = require('./symbols')

function handleRequest (err, request, reply) {
Expand All @@ -17,6 +18,7 @@ function handleRequest (err, request, reply) {

const method = request.raw.method
const headers = request.headers
const context = request[kRouteContext]

if (method === 'GET' || method === 'HEAD') {
handler(request, reply)
Expand All @@ -33,10 +35,10 @@ function handleRequest (err, request, reply) {
) { // Request has no body to parse
handler(request, reply)
} else {
reply.context.contentTypeParser.run('', handler, request, reply)
context.contentTypeParser.run('', handler, request, reply)
}
} else {
reply.context.contentTypeParser.run(contentType, handler, request, reply)
context.contentTypeParser.run(contentType, handler, request, reply)
}
return
}
Expand All @@ -49,7 +51,7 @@ function handleRequest (err, request, reply) {
headers['content-length'] !== undefined
)
) {
reply.context.contentTypeParser.run(contentType, handler, request, reply)
context.contentTypeParser.run(contentType, handler, request, reply)
} else {
handler(request, reply)
}
Expand All @@ -62,9 +64,9 @@ function handleRequest (err, request, reply) {

function handler (request, reply) {
try {
if (reply.context.preValidation !== null) {
if (request[kRouteContext].preValidation !== null) {
hookRunner(
reply.context.preValidation,
request[kRouteContext].preValidation,
hookIterator,
request,
reply,
Expand All @@ -87,9 +89,9 @@ function preValidationCallback (err, request, reply) {
return
}

const result = validateSchema(reply.context, request)
const result = validateSchema(reply[kRouteContext], request)
if (result) {
if (reply.context.attachValidation === false) {
if (reply[kRouteContext].attachValidation === false) {
reply.send(result)
return
}
Expand All @@ -98,9 +100,9 @@ function preValidationCallback (err, request, reply) {
}

// preHandler hook
if (reply.context.preHandler !== null) {
if (request[kRouteContext].preHandler !== null) {
hookRunner(
reply.context.preHandler,
request[kRouteContext].preHandler,
hookIterator,
request,
reply,
Expand All @@ -123,7 +125,7 @@ function preHandlerCallback (err, request, reply) {
let result

try {
result = reply.context.handler(request, reply)
result = request[kRouteContext].handler(request, reply)
} catch (err) {
reply[kReplyIsError] = true
reply.send(err)
Expand Down

0 comments on commit 7ffefaf

Please sign in to comment.