@fastify/reply-from 9.5.0 → 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -281,6 +281,7 @@ If a `handler` is passed to the `retryDelay` object the onus is on the client to
281
281
  - `res` is the raw response returned by the underlying agent (if available) __Note__: this object is not a Fastify response, but instead the low-level response from the agent. This property may be null if no response was obtained at all, like from a connection reset or timeout.
282
282
  - `attempt` in the object callback refers to the current retriesAttempt number. You are given the freedom to use this in concert with the retryCount property set to handle retries
283
283
  - `getDefaultRetry` refers to the default retry handler. If this callback returns not null and you wish to handle those case of errors simply invoke it as done below.
284
+ - `retriesCount` refers to the retriesCount property a client passes to reply-from. Note if the client does not explicitly set this value it will default to 0. The objective value here is to avoid hard-coding and seeing the retriesCount set. It is your perogative to ensure that you ensure the value here is as you wish (and not `0` if not intended to be as a result of a lack of not setting it).
284
285
 
285
286
  Given example
286
287
 
package/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const fp = require('fastify-plugin')
4
4
  const { lru } = require('tiny-lru')
5
5
  const querystring = require('fast-querystring')
6
+ const fastContentTypeParse = require('fast-content-type-parse')
6
7
  const Stream = require('node:stream')
7
8
  const buildRequest = require('./lib/request')
8
9
  const {
@@ -107,15 +108,13 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
107
108
  body = this.request.body
108
109
  } else {
109
110
  // Per RFC 7231 §3.1.1.5 if this header is not present we MAY assume application/octet-stream
110
- const contentType = req.headers['content-type'] || 'application/octet-stream'
111
- // detect if body should be encoded as JSON
112
- // supporting extended content-type header formats:
113
- // - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type
114
- const lowerCaseContentType = contentType.toLowerCase()
115
- const plainContentType = lowerCaseContentType.indexOf(';') > -1
116
- ? lowerCaseContentType.slice(0, lowerCaseContentType.indexOf(';'))
117
- : lowerCaseContentType
118
- const shouldEncodeJSON = contentTypesToEncode.has(plainContentType)
111
+ let contentType = 'application/octet-stream'
112
+ if (req.headers['content-type']) {
113
+ const plainContentType = fastContentTypeParse.parse(req.headers['content-type'])
114
+ contentType = plainContentType.type
115
+ }
116
+
117
+ const shouldEncodeJSON = contentTypesToEncode.has(contentType)
119
118
  // transparently support JSON encoding
120
119
  body = shouldEncodeJSON ? JSON.stringify(this.request.body) : this.request.body
121
120
  // update origin request headers after encoding
@@ -164,7 +163,7 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) {
164
163
 
165
164
  if (retryDelay) {
166
165
  requestImpl = createRequestRetry(request, this, (req, res, err, retries) => {
167
- return retryDelay({ err, req, res, attempt: retries, getDefaultDelay })
166
+ return retryDelay({ err, req, res, attempt: retries, getDefaultDelay, retriesCount })
168
167
  })
169
168
  } else {
170
169
  requestImpl = createRequestRetry(request, this, getDefaultDelay)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastify/reply-from",
3
- "version": "9.5.0",
3
+ "version": "9.7.0",
4
4
  "description": "forward your HTTP request to another server, for fastify",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -53,6 +53,7 @@
53
53
  "dependencies": {
54
54
  "@fastify/error": "^3.0.0",
55
55
  "end-of-stream": "^1.4.4",
56
+ "fast-content-type-parse": "^1.1.0",
56
57
  "fast-querystring": "^1.0.0",
57
58
  "fastify-plugin": "^4.0.0",
58
59
  "pump": "^3.0.0",
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const fastify = require('fastify')
5
+ const get = require('simple-get').concat
6
+ const From = require('..')
7
+
8
+ const upstream = fastify()
9
+ t.teardown(upstream.close.bind(upstream))
10
+ t.plan(4)
11
+
12
+ upstream.post('/test', async (request, reply) => {
13
+ if (typeof request.body === 'object') {
14
+ return 'not ok'
15
+ }
16
+ return 'ok'
17
+ })
18
+
19
+ upstream.listen({ port: 0 }, function (err) {
20
+ t.error(err)
21
+
22
+ const app = fastify()
23
+ app.register(From)
24
+ t.teardown(app.close.bind(app))
25
+
26
+ app.post('/test', (request, reply) => {
27
+ if (request.body.method === 'invalid_method') {
28
+ return reply.code(400).send({ message: 'payload contains invalid method' })
29
+ }
30
+ reply.from(`http://127.0.0.1:${upstream.server.address().port}/test`)
31
+ })
32
+
33
+ app.listen({ port: 0 }, function (err) {
34
+ t.error(err)
35
+
36
+ get({
37
+ url: `http://127.0.0.1:${app.server.address().port}/test`,
38
+ headers: { 'content-type': 'application/json ; charset=utf-8' },
39
+ // eslint-disable-next-line no-useless-escape
40
+ body: '"{\\\"method\\\":\\\"invalid_method\\\"}"',
41
+ method: 'POST'
42
+ }, (err, res, data) => {
43
+ t.error(err)
44
+ t.equal(data.toString(), 'ok')
45
+ })
46
+ })
47
+ })
@@ -160,3 +160,27 @@ test('we can exceed our retryCount and introspect attempts independently', async
160
160
  t.equal(res.statusCode, 205)
161
161
  t.equal(res.body.toString(), 'Hello World 5!')
162
162
  })
163
+
164
+ test('we handle our retries based on the retryCount', async (t) => {
165
+ const attemptCounter = []
166
+ const customRetryLogic = ({ req, res, err, attempt, getDefaultDelay, retriesCount }) => {
167
+ if (retriesCount < attempt) {
168
+ return null
169
+ }
170
+
171
+ if (res && res.statusCode === 500 && req.method === 'GET') {
172
+ attemptCounter.push(attempt)
173
+ return 0.1
174
+ }
175
+ return null
176
+ }
177
+
178
+ const { instance } = await setupServer(t, { retryDelay: customRetryLogic, retriesCount: 2 }, 500)
179
+
180
+ const res = await got.get(`http://localhost:${instance.server.address().port}`, { retry: 5 })
181
+
182
+ t.match(attemptCounter, [0, 1])
183
+ t.equal(res.headers['content-type'], 'text/plain')
184
+ t.equal(res.statusCode, 205)
185
+ t.equal(res.body.toString(), 'Hello World 5!')
186
+ })