diff --git a/README.md b/README.md index faecec730..f6c9e5214 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 + requestInterceptor: (req: Request) => Request | Promise + responseInterceptor: (res: Response) => Response | Promise }) // Custom Fetch diff --git a/src/http.js b/src/http.js index ace41b550..e13466ad1 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 @@ -25,7 +25,7 @@ export default 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 @@ -37,31 +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 - }) - - if (!res.ok) { - 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 - } - ) + 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 } - - return serialized - }) + } + 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 diff --git a/test/http.js b/test/http.js index 1623dc1e7..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')) @@ -80,6 +120,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'))