CoolFace
Apppublic

strong-tie/inbound-calls

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
ContentTypeParser.md276 linesDownload Raw Back to Reference
1<h1 align="center">Fastify</h1>2 3## `Content-Type` Parser4Natively, Fastify only supports `'application/json'` and `'text/plain'` content5types. If the content type is not one of these, an6`FST_ERR_CTP_INVALID_MEDIA_TYPE` error will be thrown.7Other common content types are supported through the use of8[plugins](https://fastify.dev/ecosystem/).9 10The default charset is `utf-8`. If you need to support different content types,11you can use the `addContentTypeParser` API. *The default JSON and/or plain text12parser can be changed or removed.*13 14*Note: If you decide to specify your own content type with the `Content-Type`15header, UTF-8 will not be the default. Be sure to include UTF-8 like this16`text/html; charset=utf-8`.*17 18As with the other APIs, `addContentTypeParser` is encapsulated in the scope in19which it is declared. This means that if you declare it in the root scope it20will be available everywhere, while if you declare it inside a plugin it will be21available only in that scope and its children.22 23Fastify automatically adds the parsed request payload to the [Fastify24request](./Request.md) object which you can access with `request.body`.25 26Note that for `GET` and `HEAD` requests the payload is never parsed. For27`OPTIONS` and `DELETE` requests the payload is only parsed if the content type28is given in the content-type header. If it is not given, the29[catch-all](#catch-all) parser is not executed as with `POST`, `PUT` and30`PATCH`, but the payload is simply not parsed.31 32> ## ⚠  Security Notice33> When using with RegExp to detect `Content-Type`, you should beware of34> how to properly detect the `Content-Type`. For example, if you need35> `application/*`, you should use `/^application\/([\w-]+);?/` to match the36> [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)37> only.38 39### Usage40```js41fastify.addContentTypeParser('application/jsoff', function (request, payload, done) {42  jsoffParser(payload, function (err, body) {43    done(err, body)44  })45})46 47// Handle multiple content types with the same function48fastify.addContentTypeParser(['text/xml', 'application/xml'], function (request, payload, done) {49  xmlParser(payload, function (err, body) {50    done(err, body)51  })52})53 54// Async is also supported in Node versions >= 8.0.055fastify.addContentTypeParser('application/jsoff', async function (request, payload) {56  const res = await jsoffParserAsync(payload)57 58  return res59})60 61// Handle all content types that matches RegExp62fastify.addContentTypeParser(/^image\/([\w-]+);?/, function (request, payload, done) {63  imageParser(payload, function (err, body) {64    done(err, body)65  })66})67 68// Can use default JSON/Text parser for different content Types69fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))70```71 72Fastify first tries to match a content-type parser with a `string` value before73trying to find a matching `RegExp`. If you provide overlapping content types,74Fastify tries to find a matching content type by starting with the last one75passed and ending with the first one. So if you want to specify a general76content type more precisely, first specify the general content type and then the77more specific one, like in the example below.78 79```js80// Here only the second content type parser is called because its value also matches the first one81fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )82fastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )83 84// Here the desired behavior is achieved because fastify first tries to match the85// `application/vnd.custom+xml` content type parser86fastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )87fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )88```89 90### Using addContentTypeParser with fastify.register91When using `addContentTypeParser` in combination with `fastify.register`,92`await` should not be used when registering routes. Using `await` causes93the route registration to be asynchronous and can lead to routes being registered94before the addContentTypeParser has been set.95 96#### Correct Usage97```js98const fastify = require('fastify')();99 100 101fastify.register((fastify, opts) => {102  fastify.addContentTypeParser('application/json', function (request, payload, done) {103    jsonParser(payload, function (err, body) {104      done(err, body)105    })106  })107 108  fastify.get('/hello', async (req, res) => {});109});110```111 112Besides the `addContentTypeParser` API there are further APIs that can be used.113These are `hasContentTypeParser`, `removeContentTypeParser` and114`removeAllContentTypeParsers`.115 116#### hasContentTypeParser117 118You can use the `hasContentTypeParser` API to find if a specific content type119parser already exists.120 121```js122if (!fastify.hasContentTypeParser('application/jsoff')){123  fastify.addContentTypeParser('application/jsoff', function (request, payload, done) {124    jsoffParser(payload, function (err, body) {125      done(err, body)126    })127  })128}129```130 131#### removeContentTypeParser132 133With `removeContentTypeParser` a single or an array of content types can be134removed. The method supports `string` and `RegExp` content types.135 136```js137fastify.addContentTypeParser('text/xml', function (request, payload, done) {138  xmlParser(payload, function (err, body) {139    done(err, body)140  })141})142 143// Removes the both built-in content type parsers so that only the content type parser for text/html is available144fastify.removeContentTypeParser(['application/json', 'text/plain'])145```146 147#### removeAllContentTypeParsers148 149In the example from just above, it is noticeable that we need to specify each150content type that we want to remove. To solve this problem Fastify provides the151`removeAllContentTypeParsers` API. This can be used to remove all currently152existing content type parsers. In the example below we achieve the same as in153the example above except that we do not need to specify each content type to154delete. Just like `removeContentTypeParser`, this API supports encapsulation.155The API is especially useful if you want to register a [catch-all content type156parser](#catch-all) that should be executed for every content type and the157built-in parsers should be ignored as well.158 159```js160fastify.removeAllContentTypeParsers()161 162fastify.addContentTypeParser('text/xml', function (request, payload, done) {163  xmlParser(payload, function (err, body) {164    done(err, body)165  })166})167```168 169**Notice**: The old syntaxes `function(req, done)` and `async function(req)` for170the parser are still supported but they are deprecated.171 172#### Body Parser173You can parse the body of a request in two ways. The first one is shown above:174you add a custom content type parser and handle the request stream. In the175second one, you should pass a `parseAs` option to the `addContentTypeParser`176API, where you declare how you want to get the body. It could be of type177`'string'` or `'buffer'`. If you use the `parseAs` option, Fastify will178internally handle the stream and perform some checks, such as the [maximum179size](./Server.md#factory-body-limit) of the body and the content length. If the180limit is exceeded the custom parser will not be invoked.181```js182fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {183  try {184    const json = JSON.parse(body)185    done(null, json)186  } catch (err) {187    err.statusCode = 400188    done(err, undefined)189  }190})191```192 193See194[`example/parser.js`](https://github.com/fastify/fastify/blob/main/examples/parser.js)195for an example.196 197##### Custom Parser Options198+ `parseAs` (string): Either `'string'` or `'buffer'` to designate how the199  incoming data should be collected. Default: `'buffer'`.200+ `bodyLimit` (number): The maximum payload size, in bytes, that the custom201  parser will accept. Defaults to the global body limit passed to the [`Fastify202  factory function`](./Server.md#bodylimit).203 204#### Catch-All205There are some cases where you need to catch all requests regardless of their206content type. With Fastify, you can just use the `'*'` content type.207```js208fastify.addContentTypeParser('*', function (request, payload, done) {209  let data = ''210  payload.on('data', chunk => { data += chunk })211  payload.on('end', () => {212    done(null, data)213  })214})215```216 217Using this, all requests that do not have a corresponding content type parser218will be handled by the specified function.219 220This is also useful for piping the request stream. You can define a content221parser like:222 223```js224fastify.addContentTypeParser('*', function (request, payload, done) {225  done()226})227```228 229and then access the core HTTP request directly for piping it where you want:230 231```js232app.post('/hello', (request, reply) => {233  reply.send(request.raw)234})235```236 237Here is a complete example that logs incoming [json238line](https://jsonlines.org/) objects:239 240```js241const split2 = require('split2')242const pump = require('pump')243 244fastify.addContentTypeParser('*', (request, payload, done) => {245  done(null, pump(payload, split2(JSON.parse)))246})247 248fastify.route({249  method: 'POST',250  url: '/api/log/jsons',251  handler: (req, res) => {252    req.body.on('data', d => console.log(d)) // log every incoming object253  }254})255 ```256 257For piping file uploads you may want to check out [this258plugin](https://github.com/fastify/fastify-multipart).259 260If you want the content type parser to be executed on all content types and not261only on those that don't have a specific one, you should call the262`removeAllContentTypeParsers` method first.263 264```js265// Without this call, the request body with the content type application/json would be processed by the built-in JSON parser266fastify.removeAllContentTypeParsers()267 268fastify.addContentTypeParser('*', function (request, payload, done) {269  const data = ''270  payload.on('data', chunk => { data += chunk })271  payload.on('end', () => {272    done(null, data)273  })274})275```276