From e402f5f4a859420259934997d2e92a36056b05a1 Mon Sep 17 00:00:00 2001 From: Rolf Grossmann Date: Wed, 14 Mar 2018 15:39:54 +0100 Subject: [PATCH 1/3] Let responseInterceptor properly return a Promise and use the new result to determine error. --- README.md | 2 +- src/http.js | 26 ++++++++++++-------------- test/http.js | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6bb2c4a83..1dcea97ee 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ Swagger.http(request) // Interceptors Swagger.http({ requestInterceptor: (req: Request) => Request - responseInterceptor: (res: Response) => Response + responseInterceptor: (res: Response) => Response | Promise }) // Custom Fetch diff --git a/src/http.js b/src/http.js index ace41b550..aebed3ba3 100644 --- a/src/http.js +++ b/src/http.js @@ -43,22 +43,20 @@ export default function http(url, request = {}) { _res = request.responseInterceptor(_res) || _res } return _res - }) - - if (!res.ok) { + }).then((_res) => { + if (!_res.ok) { + const error = new Error(_res.statusText) + error.statusCode = error.status = _res.status + error.response = _res + throw error + } + return _res + }, (resError) => { const error = new Error(res.statusText) error.statusCode = error.status = res.status - return serialized.then( - (_res) => { - error.response = _res - throw error - }, - (resError) => { - error.responseError = resError - throw error - } - ) - } + error.responseError = resError + throw error + }) return serialized }) diff --git a/test/http.js b/test/http.js index 1623dc1e7..e9083c3fb 100644 --- a/test/http.js +++ b/test/http.js @@ -80,6 +80,25 @@ describe('http', () => { ) }) + it('should allow the responseInterceptor to return a promise for a final response', () => { + xapp = xmock() + xapp.get('http://swagger.io', (req, res) => res.status(400).send('doit')) + xapp.get('http://example.com', (req, res) => res.send('hi')) + + return http({ + url: 'http://swagger.io', + responseInterceptor: (res) => { + return http({ + url: 'http://example.com' + }) + } + }) + .then((res) => { + expect(res.status).toEqual(200) + expect(res.text).toEqual('hi') + }) + }) + it('should set responseError on responseInterceptor Error', () => { xapp = xmock() xapp.get('http://swagger.io', (req, res) => res.status(400).send('hi')) From 3d7653a79700a8c007f333687596800f012378e2 Mon Sep 17 00:00:00 2001 From: Rolf Grossmann Date: Fri, 16 Mar 2018 09:11:27 +0100 Subject: [PATCH 2/3] Rewrite http function to use async/await as requested. It does make the responseInterceptor code much easier to read ;) --- src/http.js | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/http.js b/src/http.js index aebed3ba3..51aff49a9 100644 --- a/src/http.js +++ b/src/http.js @@ -1,4 +1,4 @@ -import 'cross-fetch/polyfill' +import 'cross-fetch/polyfill' /* global fetch */ import qs from 'qs' import jsYaml from 'js-yaml' import isString from 'lodash/isString' @@ -11,7 +11,7 @@ export const self = { // Handles fetch-like syntax and the case where there is only one object passed-in // (which will have the URL as a property). Also serilizes the response. -export default function http(url, request = {}) { +export default async function http(url, request = {}) { if (typeof url === 'object') { request = url url = request.url @@ -37,29 +37,27 @@ export default function http(url, request = {}) { } // eslint-disable-next-line no-undef - return (request.userFetch || fetch)(request.url, request).then((res) => { - const serialized = self.serializeRes(res, url, request).then((_res) => { - if (request.responseInterceptor) { - _res = request.responseInterceptor(_res) || _res - } - return _res - }).then((_res) => { - if (!_res.ok) { - const error = new Error(_res.statusText) - error.statusCode = error.status = _res.status - error.response = _res - throw error - } - return _res - }, (resError) => { - const error = new Error(res.statusText) - error.statusCode = error.status = res.status - error.responseError = resError - throw error - }) - - return serialized - }) + let res + try { + res = await (request.userFetch || fetch)(request.url, request) + res = await self.serializeRes(res, url, request) + if (request.responseInterceptor) { + res = await request.responseInterceptor(res) || res + } + } + catch (resError) { + const error = new Error(res.statusText) + error.statusCode = error.status = res.status + error.responseError = resError + throw error + } + if (!res.ok) { + const error = new Error(res.statusText) + error.statusCode = error.status = res.status + error.response = res + throw error + } + return res } // exported for testing From 499a1df5f1f6797984227f7ec06a95c07eab732c Mon Sep 17 00:00:00 2001 From: Date: Tue, 20 Mar 2018 20:03:19 +0100 Subject: [PATCH 3/3] Support asynchronous requestInterceptor aswell, including tests. Fixes #1249. --- README.md | 4 ++-- src/http.js | 2 +- test/http.js | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 636c888c2..f08c68ed0 100644 --- a/README.md +++ b/README.md @@ -95,8 +95,8 @@ Swagger.http(request) // Interceptors Swagger.http({ - requestInterceptor: (req: Request) => Request - responseInterceptor: (res: Response) => Response | Promise + requestInterceptor: (req: Request) => Request | Promise + responseInterceptor: (res: Response) => Response | Promise }) // Custom Fetch diff --git a/src/http.js b/src/http.js index 51aff49a9..e13466ad1 100644 --- a/src/http.js +++ b/src/http.js @@ -25,7 +25,7 @@ export default async function http(url, request = {}) { self.mergeInQueryOrForm(request) if (request.requestInterceptor) { - request = request.requestInterceptor(request) || request + request = await request.requestInterceptor(request) || request } // for content-type=multipart\/form-data remove content-type from request before fetch diff --git a/test/http.js b/test/http.js index e9083c3fb..1370e13c1 100644 --- a/test/http.js +++ b/test/http.js @@ -60,6 +60,46 @@ describe('http', () => { ) }) + it('should call request interceptor', () => { + xapp = xmock() + xapp.get('http://swagger.io', (req, res) => res.status(req.requestHeaders.mystatus).send('hi')) + + return http({ + url: 'http://swagger.io', + requestInterceptor: (req) => { + req.headers.mystatus = 200 + return req + } + }) + .then( + (res) => { + expect(res.status).toEqual(200) + } + ) + }) + + it('should allow the requestInterceptor to return a promise', () => { + xapp = xmock() + xapp.get('http://swagger.io', (req, res) => res.status(req.requestHeaders.mystatus).send('hi')) + + return http({ + url: 'http://swagger.io', + requestInterceptor: (req) => { + return new Promise((resolve, reject) => { + setTimeout(() => { + req.headers.mystatus = 200 + resolve(req) + }, 20) + }) + } + }) + .then( + (res) => { + expect(res.status).toEqual(200) + } + ) + }) + it('should apply responseInterceptor to error responses', () => { xapp = xmock() xapp.get('http://swagger.io', (req, res) => res.status(400).send('hi'))