Extending request body parsing

Parsing requests

LoopBack 4 uses the Content-Type header and requestBody of the OpenAPI specto parse the body of http requests. Please seeParsing requests for more details.

The @loopback/rest module ships a set of built-in body parsers:

  • json: parses the http request body as a json value (object, array, string,number, boolean, null)
  • urlencoded: decodes the http request body from‘application/x-www-form-urlencoded’
  • text: parses the http request body as a string
  • stream: keeps the http request body as a stream without parsing
  • raw: parses the http request body as a BufferTo support more media types, LoopBack defines extension points to plug in bodyparsers to parse the request body. LoopBack‘s request body parsing capabilitycan be extended in the following ways:

Adding a new parser

To add a new body parser, follow the steps below:

  • Define a class that implements the BodyParser interface:
/**
 * Interface to be implemented by body parser extensions
 */
export interface BodyParser {
  /**
   * Name of the parser
   */
  name: string | symbol;
  /**
   * Indicate if the given media type is supported
   * @param mediaType - Media type
   */
  supports(mediaType: string): boolean;
  /**
   * Parse the request body
   * @param request - http request
   */
  parse(request: Request): Promise<RequestBody>;
}

A body parser implementation class will be instantiated by the LoopBack runtimewithin the context and it can leverage dependency injections. For example:

export class JsonBodyParser implements BodyParser {
  name = 'json';
  private jsonParser: BodyParserMiddleware;

  constructor(
    @inject(RestBindings.REQUEST_BODY_PARSER_OPTIONS, {optional: true})
    options: RequestBodyParserOptions = {},
  ) {
    const jsonOptions = getParserOptions('json', options);
    this.jsonParser = json(jsonOptions);
  }
  // ...
}

See the complete code athttps://github.com/strongloop/loopback-next/blob/master/packages/rest/src/body-parsers/body-parser.json.ts.

  • Bind the body parser class to your REST server/application:For example,
server.bodyParser(XmlBodyParser);

The bodyParser api binds XmlBodyParser to the context with:

  • key: request.bodyParser.XmlBodyParser
  • tag: request.bodyParserPlease note that newly added body parsers are always invoked before the built-inones.

Contribute a body parser from a component

A component can add one or more body parsers via its bindings property:

import {createBodyParserBinding} from '@loopback/rest';

export class XmlComponent implements Component {
  bindings = [createBodyParserBinding(XmlBodyParser)];
}

Customize parser options

The request body parser options is bound toRestBindings.REQUEST_BODY_PARSER_OPTIONS. To customize request body parseroptions, you can simply bind a new value to its key.

Built-in parsers retrieve their own options from the request body parseroptions. The parser specific properties override common ones. For example, giventhe following configuration:

{
  limit: '1MB'
  json: {
    strict: false
  },
  text: {
    limit: '2MB'
  },
  /**
   * Validation options for AJV, see https://github.com/epoberezkin/ajv#options
   * This setting is global for all request body parsers and it cannot be
   * overridden inside parser specific properties such as `json` or `text`.
   */
  validation: {nullable: true},
}

The json parser will be created with {limit: '1MB', strict: false} and thetext parser with {limit: '2MB'}.

Custom parsers can choose to have its own options from the context bydependency injection, for example:

export class XmlBodyParser implements BodyParser {
  name = 'xml';

  constructor(
    @inject('request.bodyParsers.xml.options', {optional: true})
    options: XmlBodyParserOptions = {},
  ) {
    ...
  }
  // ...
}

Replace an existing parser

An existing parser can be replaced by binding a different value to theapplication context.

class MyJsonBodyParser implements BodyParser {
  // ...
}
app.bodyParser(MyJsonBodyParser, RestBindings.REQUEST_BODY_PARSER_JSON);

Remove an existing parser

An existing parser can be removed from the application by unbinding thecorresponding key. For example, the following code removes the built-in JSONbody parser.

app.unbind(RestBindings.REQUEST_BODY_PARSER_JSON);