Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ Swagger.http(request)

// Interceptors
Swagger.http({
requestInterceptor: (req: Request) => Request
responseInterceptor: (res: Response) => Response
requestInterceptor: (req: Request) => Request | Promise<Request>
responseInterceptor: (res: Response) => Response | Promise<Response>
})

// Custom Fetch
Expand Down
50 changes: 23 additions & 27 deletions src/http.js
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
59 changes: 59 additions & 0 deletions test/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'))
Expand All @@ -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'))
Expand Down