Permalink
Browse files

feat: interceptor helpers

  • Loading branch information...
pi0 committed Jan 28, 2018
1 parent 6f2fa08 commit fa3eb473b50df3e455b01d48fb78a3a622184f88
Showing with 138 additions and 104 deletions.
  1. +99 −86 README.md
  2. +24 −10 lib/plugin.template.js
  3. +3 −7 test/axios.test.js
  4. +4 −1 test/fixture/nuxt.config.js
  5. +8 −0 test/fixture/plugins/axios.js
185 README.md
@@ -38,6 +38,12 @@
* [Component](#component)
* [Store](#store-nuxtserverinit)
* [Store Actions](#store-actions)
* [Extending Axios](#extending-axios)
* [Helpers](#helpers)
* [Middleware](#middleware)
* [Fetch Style Requests](#fetch-style-requests)
* [Set Header](#setheadername-value-scopescommon)
* [Set Token](#settokentoken-type-scopescommon)
* [Options](#options)
* [Prefix, Host and Port](#prefix-host-and-port)
* [baseURL](#baseurl)
@@ -47,11 +53,6 @@
* [proxyHeaders](#proxyheaders)
* [proxyHeadersIgnore](#proxyheadersignore)
* [disableDefaultErrorHandler](#disabledefaulterrorhandler)
* [Helpers](#helpers)
* [Fetch Style Requests](#fetch-style-requests)
* [Set Header](#setheadername-value-scopescommon)
* [Set Token](#settokentoken-type-scopescommon)
* [Dynamic API Backend](#dynamic-api-backend)

## Features

@@ -137,102 +138,56 @@ async nuxtServerInit ({ commit }, { app }) {
}
```

## Options

You can pass options using module options or `axios` section in `nuxt.config.js`
## Extending Axios

### `prefix`, `host` and `port`

This options are used for default values of `baseURL` and `browserBaseURL`.

Can be customized with `API_PREFIX`, `API_HOST` (or `HOST`) and `API_PORT` (or `PORT`) environment variables.

Default value of `prefix` is `/`.
If you need to customize axios by registering interceptors and changing global config, you have to create a nuxt plugin.

### `baseURL`

* Default: `http://[HOST]:[PORT][PREFIX]`

Base URL which is used and prepended to make requests in server side.

Environment variable `API_URL` can be used to **override** `baseURL`.

### `browserBaseURL`

* Default: `baseURL` (or `prefix` when `options.proxyMode` is `true`)

Base URL which is used and prepended to make requests in client side.

Environment variable `API_URL_BROWSER` can be used to **override** `browserBaseURL`.

### `credentials`

* Default: `false`

Adds an interceptor to automatically set `withCredentials` config of axios when requesting to `baseUrl`
which allows passing authentication headers to backend.

### `debug`

* Default: `false`

Adds interceptors to log all responses and requests

### `proxyHeaders`

* Default: `true`

In SSR context, sets client request header as axios default request headers.
This is useful for making requests which need cookie based auth on server side.
Also helps making consistent requests in both SSR and Client Side code.

> **NOTE:** If directing requests at a url protected by CloudFlare's CDN you should set this to false to prevent CloudFlare from mistakenly detecting a reverse proxy loop and returning a 403 error.
### `proxyHeadersIgnore`

* Default `['host', 'accept']`

Only efficient when `proxyHeaders` is set to true. Removes unwanted request headers to the API backend in SSR.

### `redirectError`
**nuxt.config.js**

* Default: `{}`
```js
modules: [
'@nuxtjs/axios',
],
plugins: [
'~/plugins/axios'
]
```

This option is a map from specific error codes to page which they should be redirect.
For example if you want redirecting all `401` errors to `/login` use:
**plugins/axios.js**

```js
axios: {
redirectError: {
401: '/login'
}
export default function ({ $axios, redirect }) {
$axios.onRequest(config => {
console.log('Making request to ' + config.url)
})
}
```

### `requestInterceptor`
## Helpers

* Default: `null`
### Interceptors

Function for manipulating axios requests. Useful for setting custom headers,
for example based on the store state. The second argument is the nuxt context.
Axios plugin provides helpers to register axios interceptors easier and faster.

```js
requestInterceptor: (config, { store }) => {
if (store.state.token) {
config.headers.common['Authorization'] = store.state.token
}
return config
}
```
- `onRequest(config)`
- `onResponse(response)`
- `onError(err)`
- `onRequestError(err)`
- `onResponseError(err)`

### `disableDefaultErrorHandler`
This functions don't have to return anything by default.

* Default: `false`

If you want to disable the default error handler for some reason, you can do it so
by setting the option `disableDefaultErrorHandler` to true.
Example: (`plugins/axios.js`)

## Helpers
```js
export default function ({ $axios, redirect }) {
$axios.onError(error => {
if(error.code === 500) {
redirect('/sorry')
}
})
}
```

### Fetch Style requests

@@ -305,6 +260,64 @@ this.$axios.setToken('123', 'Bearer', ['post', 'delete'])
this.$axios.setToken(false)
```

## Options

You can pass options using module options or `axios` section in `nuxt.config.js`

### `prefix`, `host` and `port`

This options are used for default values of `baseURL` and `browserBaseURL`.

Can be customized with `API_PREFIX`, `API_HOST` (or `HOST`) and `API_PORT` (or `PORT`) environment variables.

Default value of `prefix` is `/`.

### `baseURL`

* Default: `http://[HOST]:[PORT][PREFIX]`

Base URL which is used and prepended to make requests in server side.

Environment variable `API_URL` can be used to **override** `baseURL`.

### `browserBaseURL`

* Default: `baseURL` (or `prefix` when `options.proxyMode` is `true`)

Base URL which is used and prepended to make requests in client side.

Environment variable `API_URL_BROWSER` can be used to **override** `browserBaseURL`.

### `credentials`

* Default: `false`

Adds an interceptor to automatically set `withCredentials` config of axios when requesting to `baseUrl`
which allows passing authentication headers to backend.

### `debug`

* Default: `false`

Adds interceptors to log request and responses.

### `proxyHeaders`

* Default: `true`

In SSR context, sets client request header as axios default request headers.
This is useful for making requests which need cookie based auth on server side.
Also helps making consistent requests in both SSR and Client Side code.

> **NOTE:** If directing requests at a url protected by CloudFlare's CDN you should set this to false to prevent CloudFlare from mistakenly detecting a reverse proxy loop and returning a 403 error.
### `proxyHeadersIgnore`

* Default `['host', 'accept']`

Only efficient when `proxyHeaders` is set to true. Removes unwanted request headers to the API backend in SSR.


## License

[MIT License](./LICENSE) - Copyright (c) 2017 Nuxt Community
@@ -14,6 +14,22 @@ const axiosExtra = {
setToken (token, type, scopes = 'common') {
const value = !token ? null : (type ? type + ' ' : '') + token
this.setHeader('Authorization', value, scopes)
},
onRequest(fn) {
this.interceptors.request.use(config => fn(config) || config)
},
onResponse(fn) {
this.interceptors.response.use(response => fn(response) || response)
},
onRequestError(fn) {
this.interceptors.request.use(undefined, error => fn(error) || Promise.reject(error))
},
onResponseError(fn) {
this.interceptors.response.use(undefined, error => fn(error) || Promise.reject(error))
},
onError(fn) {
this.onRequestError(fn)
this.onResponseError(fn)
}
}

@@ -33,13 +49,15 @@ const log = (level, ...messages) => console[level]('[Axios]', ...messages)

const setupDebugInterceptor = axios => {
// request
axios.interceptors.request.use(undefined, error => {
log('error', 'Request error:', error)
return Promise.reject(error)
axios.onRequestError(error => {
log('error', 'Request error:', error)
})

// response
axios.interceptors.response.use(res => {
axios.onResponseError(error => {
log('error', 'Response error:', error)
})
axios.onResponse(res => {
log(
'info',
'[' + (res.status + ' ' + res.statusText) + ']',
@@ -53,28 +71,24 @@ const setupDebugInterceptor = axios => {
}

return res
}, error => {
log('error', 'Response error:', error)
return Promise.reject(error)
})
}
<% } %>

<% if (options.credentials) { %>
const setupCredentialsInterceptor = axios => {
// Send credentials only to relative and API Backend requests
axios.interceptors.request.use(config => {
axios.onRequest(config => {
if (config.withCredentials === undefined) {
if (!/^https?:\/\//i.test(config.url) || config.url.indexOf(config.baseURL) === 0) {
config.withCredentials = true
}
}
return config
})
}
<% } %>

export default async (ctx, inject) => {
export default (ctx, inject) => {
const axiosOptions = {
// baseURL
baseURL : process.browser
@@ -1,12 +1,8 @@
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000
process.env.PORT = process.env.PORT || 5060
process.env.NODE_ENV = 'production'

const { Nuxt, Builder } = require('nuxt')
const axios = require('axios')
const config = require('./fixture/nuxt.config')

const url = path => `http://localhost:${process.env.PORT}${path}`
const url = path => `http://localhost:3000${path}`

describe('axios module', () => {
let nuxt
@@ -22,7 +18,7 @@ describe('axios module', () => {

await new Builder(nuxt).build()
await nuxt.listen(process.env.PORT)
})
}, 60000)

afterAll(async () => {
await nuxt.close()
@@ -35,7 +31,7 @@ describe('axios module', () => {
)
let options = call[0].options
expect(options.baseURL.toString()).toBe(
`http://localhost:${process.env.PORT}/test_api`
`http://localhost:3000/test_api`
)
expect(options.browserBaseURL.toString()).toBe('/test_api')
})
@@ -14,5 +14,8 @@ module.exports = {
proxyMode: true,
credentials: true,
debug: true
}
},
plugins: [
'~/plugins/axios'
]
}
@@ -0,0 +1,8 @@
export default function ({ $axios, redirect }) {
$axios.onRequest(config => {
// eslint-disable-next-line no-console
console.log('SPY: ' + config.url)

$axios.defaults.xsrfHeaderName = 'X-CSRF-TOKEN'
})
}

0 comments on commit fa3eb47

Please sign in to comment.