src/router.js
function httpRouter(req, res) {
        let operation;
        let responseSpec = defaultResponseSpec;

        return httpTransaction(req, res)
          .then(([request, transaction]) =>
            transaction
              .start(() =>
                Promise.resolve()
                  .then(() => {
                    const method = request.method;
                    const path = request.url.split(SEARCH_SEPARATOR)[0];
                    const search = request.url.substr(path.length);
                    const parts = path.split('/').filter(a => a);
                    let [result, pathParameters] = routers[method]
                      ? routers[method].find(parts)
                      : [];

                    // Second chance for HEAD calls
                    if (!result && 'head' === method) {
                      [result, pathParameters] = routers.get
                        ? routers.get.find(parts)
                        : [];
                    }

                    const { handler, operation: _operation_, validators } =
                      result || {};

                    if (!handler) {
                      log('debug', 'No handler found for: ', method, parts);
                      throw new HTTPError(404, 'E_NOT_FOUND', method, parts);
                    }

                    operation = _operation_;

                    return {
                      search,
                      pathParameters,
                      validators,
                      operation,
                      handler,
                    };
                  })
                  .then(
                    ({
                      search,
                      pathParameters,
                      validators,
                      operation,
                      handler,
                    }) => {
                      const consumableMediaTypes =
                        operation.consumes || API.consumes || [];
                      const produceableMediaTypes =
                        (operation && operation.produces) || API.produces || [];
                      const bodySpec = extractBodySpec(
                        request,
                        consumableMediaTypes,
                        consumableCharsets,
                      );
                      responseSpec = extractResponseSpec(
                        operation,
                        request,
                        produceableMediaTypes,
                        produceableCharsets,
                      );

                      return getBody(
                        {
                          DECODERS,
                          PARSERS,
                          bufferLimit,
                        },
                        operation,
                        request.body,
                        bodySpec,
                      )
                        .then(body =>
                          Object.assign(
                            body ? { body } : {},
                            pathParameters,
                            QUERY_PARSER(operation.parameters, search),
                            filterHeaders(
                              operation.parameters,
                              request.headers,
                            ),
                          ),
                        )
                        .then(parameters => {
                          applyValidators(operation, validators, parameters);
                          return parameters;
                        })
                        .catch(err => {
                          throw HTTPError.cast(err, 400);
                        })
                        .then(executeHandler.bind(null, operation, handler))
                        .then(response => {
                          if (response.body) {
                            response.headers['content-type'] =
                              response.headers['content-type'] ||
                              responseSpec.contentTypes[0];
                          }

                          // Check the stringifyer only when a schema is
                          // specified
                          const responseHasSchema =
                            operation.responses &&
                            operation.responses[response.status] &&
                            operation.responses[response.status].schema;

                          if (
                            responseHasSchema &&
                            !STRINGIFYERS[response.headers['content-type']]
                          ) {
                            return Promise.reject(
                              new HTTPError(
                                500,
                                'E_STRINGIFYER_LACK',
                                response.headers['content-type'],
                              ),
                            );
                          }
                          if (response.body) {
                            checkResponseCharset(
                              request,
                              responseSpec,
                              produceableCharsets,
                            );
                            checkResponseMediaType(
                              request,
                              responseSpec,
                              produceableMediaTypes,
                            );
                          }

                          return response;
                        });
                    },
                  ),
              )
              .catch(transaction.catch)
              .catch(errorHandler.bind(null, transaction.id, responseSpec))
              .then(response => {
                if (response.body && 'head' === request.method) {
                  log(
                    'warning',
                    'Body stripped:',
                    response.body instanceof Stream ? 'Stream' : response.body,
                  );
                  return Object.keys(response)
                    .filter(key => 'body' !== key)
                    .reduce((cleanedResponse, key) => {
                      cleanedResponse[key] = response[key];
                      return cleanedResponse;
                    }, {});
                }
                return response;
              })
              // Here sendBody is not binded since we need
              // the `operation` value at the exact moment
              // of the then stage execution
              .then(response =>
                sendBody(
                  {
                    DEBUG_NODE_ENVS,
                    ENV,
                    API,
                    ENCODERS,
                    STRINGIFYERS,
                    log,
                    ajv,
                  },
                  operation,
                  response,
                ),
              )
              .then(transaction.end),
          )
          .catch(handleFatalError);
      }
function httpRouter(req, res) {
        let operation;
        let responseSpec = defaultResponseSpec;

        return httpTransaction(req, res)
          .then(([request, transaction]) =>
            transaction
              .start(() =>
                Promise.resolve()
                  .then(() => {
                    const method = request.method;
                    const path = request.url.split(SEARCH_SEPARATOR)[0];
                    const search = request.url.substr(path.length);
                    const parts = path.split('/').filter(a => a);
                    let [result, pathParameters] = routers[method]
                      ? routers[method].find(parts)
                      : [];

                    // Second chance for HEAD calls
                    if (!result && 'head' === method) {
                      [result, pathParameters] = routers.get
                        ? routers.get.find(parts)
                        : [];
                    }

                    const { handler, operation: _operation_, validators } =
                      result || {};

                    if (!handler) {
                      log('debug', 'No handler found for: ', method, parts);
                      throw new HTTPError(404, 'E_NOT_FOUND', method, parts);
                    }

                    operation = _operation_;

                    return {
                      search,
                      pathParameters,
                      validators,
                      operation,
                      handler,
                    };
                  })
                  .then(
                    ({
                      search,
                      pathParameters,
                      validators,
                      operation,
                      handler,
                    }) => {
                      const consumableMediaTypes =
                        operation.consumes || API.consumes || [];
                      const produceableMediaTypes =
                        (operation && operation.produces) || API.produces || [];
                      const bodySpec = extractBodySpec(
                        request,
                        consumableMediaTypes,
                        consumableCharsets,
                      );
                      responseSpec = extractResponseSpec(
                        operation,
                        request,
                        produceableMediaTypes,
                        produceableCharsets,
                      );

                      return getBody(
                        {
                          DECODERS,
                          PARSERS,
                          bufferLimit,
                        },
                        operation,
                        request.body,
                        bodySpec,
                      )
                        .then(body =>
                          Object.assign(
                            body ? { body } : {},
                            pathParameters,
                            QUERY_PARSER(operation.parameters, search),
                            filterHeaders(
                              operation.parameters,
                              request.headers,
                            ),
                          ),
                        )
                        .then(parameters => {
                          applyValidators(operation, validators, parameters);
                          return parameters;
                        })
                        .catch(err => {
                          throw HTTPError.cast(err, 400);
                        })
                        .then(executeHandler.bind(null, operation, handler))
                        .then(response => {
                          if (response.body) {
                            response.headers['content-type'] =
                              response.headers['content-type'] ||
                              responseSpec.contentTypes[0];
                          }

                          // Check the stringifyer only when a schema is
                          // specified
                          const responseHasSchema =
                            operation.responses &&
                            operation.responses[response.status] &&
                            operation.responses[response.status].schema;

                          if (
                            responseHasSchema &&
                            !STRINGIFYERS[response.headers['content-type']]
                          ) {
                            return Promise.reject(
                              new HTTPError(
                                500,
                                'E_STRINGIFYER_LACK',
                                response.headers['content-type'],
                              ),
                            );
                          }
                          if (response.body) {
                            checkResponseCharset(
                              request,
                              responseSpec,
                              produceableCharsets,
                            );
                            checkResponseMediaType(
                              request,
                              responseSpec,
                              produceableMediaTypes,
                            );
                          }

                          return response;
                        });
                    },
                  ),
              )
              .catch(transaction.catch)
              .catch(errorHandler.bind(null, transaction.id, responseSpec))
              .then(response => {
                if (response.body && 'head' === request.method) {
                  log(
                    'warning',
                    'Body stripped:',
                    response.body instanceof Stream ? 'Stream' : response.body,
                  );
                  return Object.keys(response)
                    .filter(key => 'body' !== key)
                    .reduce((cleanedResponse, key) => {
                      cleanedResponse[key] = response[key];
                      return cleanedResponse;
                    }, {});
                }
                return response;
              })
              // Here sendBody is not binded since we need
              // the `operation` value at the exact moment
              // of the then stage execution
              .then(response =>
                sendBody(
                  {
                    DEBUG_NODE_ENVS,
                    ENV,
                    API,
                    ENCODERS,
                    STRINGIFYERS,
                    log,
                    ajv,
                  },
                  operation,
                  response,
                ),
              )
              .then(transaction.end),
          )
          .catch(handleFatalError);
      }
Handle an HTTP incoming message
@param  {HTTPRequest}  req
A raw NodeJS HTTP incoming message
@param  {HTTPResponse} res
A raw NodeJS HTTP response
@return {Promise}
A promise resolving when the operation
completes