sam522's picture
node
d4b85c0
import { invariant } from 'outvariant'
import { DeferredPromise } from '@open-draft/deferred-promise'
import { InterceptorError } from './InterceptorError'
const kRequestHandled = Symbol('kRequestHandled')
export const kResponsePromise = Symbol('kResponsePromise')
export class RequestController {
/**
* Internal response promise.
* Available only for the library internals to grab the
* response instance provided by the developer.
* @note This promise cannot be rejected. It's either infinitely
* pending or resolved with whichever Response was passed to `respondWith()`.
*/
[kResponsePromise]: DeferredPromise<Response | Error | undefined>;
/**
* Internal flag indicating if this request has been handled.
* @note The response promise becomes "fulfilled" on the next tick.
*/
[kRequestHandled]: boolean
constructor(private request: Request) {
this[kRequestHandled] = false
this[kResponsePromise] = new DeferredPromise()
}
/**
* Respond to this request with the given `Response` instance.
* @example
* controller.respondWith(new Response())
* controller.respondWith(Response.json({ id }))
* controller.respondWith(Response.error())
*/
public respondWith(response: Response): void {
invariant.as(
InterceptorError,
!this[kRequestHandled],
'Failed to respond to the "%s %s" request: the "request" event has already been handled.',
this.request.method,
this.request.url
)
this[kRequestHandled] = true
this[kResponsePromise].resolve(response)
/**
* @note The request conrtoller doesn't do anything
* apart from letting the interceptor await the response
* provided by the developer through the response promise.
* Each interceptor implements the actual respondWith/errorWith
* logic based on that interceptor's needs.
*/
}
/**
* Error this request with the given error.
* @example
* controller.errorWith()
* controller.errorWith(new Error('Oops!'))
*/
public errorWith(error?: Error): void {
invariant.as(
InterceptorError,
!this[kRequestHandled],
'Failed to error the "%s %s" request: the "request" event has already been handled.',
this.request.method,
this.request.url
)
this[kRequestHandled] = true
/**
* @note Resolve the response promise, not reject.
* This helps us differentiate between unhandled exceptions
* and intended errors ("errorWith") while waiting for the response.
*/
this[kResponsePromise].resolve(error)
}
}