UNPKG

lux-framework

Version:

Build scalable, Node.js-powered REST APIs with almost no code.

146 lines (114 loc) 3.48 kB
// @flow import { createServer } from 'http'; import type { Writable } from 'stream'; import type { IncomingMessage, Server as HTTPServer } from 'http'; // eslint-disable-line max-len, no-duplicate-imports import { tryCatchSync } from '../../utils/try-catch'; import type Logger from '../logger'; import type Router from '../router'; import { HAS_BODY } from './constants'; import { createRequest, parseRequest } from './request'; import { createResponse } from './response'; import { createResponder } from './responder'; import validateAccept from './utils/validate-accept'; import validateContentType from './utils/validate-content-type'; import setCORSHeaders from './utils/set-cors-headers'; import type { Request } from './request/interfaces'; import type { Response } from './response/interfaces'; import type { Server$opts, Server$cors } from './interfaces'; /** * @private */ class Server { logger: Logger; router: Router; cors: Server$cors; instance: HTTPServer; constructor({ logger, router, cors }: Server$opts) { Object.defineProperties(this, { router: { value: router, writable: false, enumerable: false, configurable: false }, logger: { value: logger, writable: false, enumerable: false, configurable: false }, cors: { value: cors, writable: false, enumerable: false, configurable: false }, instance: { value: createServer(this.receiveRequest), writable: false, enumerable: false, configurable: false } }); } listen(port: number): void { this.instance.listen(port); } initializeRequest(req: IncomingMessage, res: Writable): [Request, Response] { const { logger, router, cors } = this; req.setEncoding('utf8'); const response = createResponse(res, { logger }); setCORSHeaders(response, cors); const request = createRequest(req, { logger, router }); return [request, response]; } validateRequest({ method, headers }: Request): true { let isValid = validateAccept(headers.get('accept')); if (HAS_BODY.test(method)) { isValid = validateContentType(headers.get('content-type')); } return isValid; } receiveRequest = (req: IncomingMessage, res: Writable): void => { const { logger } = this; const [request, response] = this.initializeRequest(req, res); const respond = createResponder(request, response); logger.request(request, response, { startTime: Date.now() }); const isValid = tryCatchSync(() => this.validateRequest(request), respond); if (isValid) { parseRequest(request) .then(params => { const { route } = request; Object.assign(request, { params }); if (route) { return route.visit(request, response); } return undefined; }) .then(respond) .catch(err => { logger.error(err); respond(err); }); } } } export default Server; export { REQUEST_METHODS, getDomain } from './request'; export { default as createServerError } from './utils/create-server-error'; export type { Server$config } from './interfaces'; export type { Request, Request$params, Request$method } from './request/interfaces'; export type { Response } from './response/interfaces';