npm i apisaue --save or yarn add apisauce
// showLastCommitMessageForThisLibrary.js
import { create } from 'apisauce'
// define the api
const api = create({
baseURL: 'https://api.github.com',
headers: { Accept: 'application/vnd.github.v3+json' },
})
// start making calls
api
.get('/repos/skellock/apisauce/commits')
.then(response => response.data[0].commit.message)
.then(console.log)
// customizing headers per-request
api.post('/users', { name: 'steve' }, { headers: { 'x-gigawatts': '1.21' } })
You create an api by calling .create() and passing in a configurtion object.
const api = create({ baseURL: 'https://api.github.com' })
필수 속성은 baseURL이다. 그리고 API의 starting point이다. It can contain a sub-path and a post as well.
const api = create({ baseURL: 'https://example.com/api/v3' })
HTTP request headers for all requests can be included as well.
const api = create({
baseURL: '...',
headers: {
'X-API-KEY': '123',
'X-MARKS-THE-SPOT': 'yarrrrr',
},
})
Default timeouts can be applied too: (api로부터 response 대기 시간)
const api = create({ baseURL: '...', timeout: 30000 }) // 30 seconds
You can also pass an already created axios instance
import axios from 'axios'
import { create } from 'apisauce'
const customAxiosInstance = axios.create({ baseURL: 'https://example.com/api/v3' })
const apisauceInstance = create({ axiosInstance: customAxiosInstance })
With your fresh api, you can now call it like this:"
api.get('/repos/skellock/apisauce/commits')
api.head('/me')
api.delete('/users/69')
api.post('/todos', { note: 'jump around' }, { headers: { 'x-ray': 'machine' } })
api.patch('/servers/1', { live: false })
api.put('/servers/1', { live: true })
api.link('/images/my_dog.jpg', {}, { headers: { Link: '<http://example.com/profiles/joe>; rel="tag"' } })
api.unlink('/images/my_dog.jpg', {}, { headers: { Link: '<http://example.com/profiles/joe>; rel="tag"' } })
api.any({ method: 'GET', url: '/product', params: { id: 1 } })
get, head, delete, link and unlink accept 3 parameters:
post, put, and patch accept 3 different parameters:
any only accept one parameter
response들은 pomised_based이다, 그래서 .then() functio 안에서 이걸 handle할 필요가 있다.
The promised is always resolved with a response object.
Even if there was a problem with the request! This is one of the goals of this library. It ensures sane calling code without having to handle .catch and have 2 separate flows.
A response will always have these 2 properties:
ok - Boolean - True if the status code is in the 200's; false otherwise.
problem - String - One of 6 different values (see below - problem codes)
If the request made it to the server and got a response of nay kind, response will also have these properties:
data - Object - this is probably the thing you're after.
status - Number - the HTTP response code
headers - Object - the HTTP response headers
config - Object - the `axios` config object used to make the request
duration - Number - the number of milliseconds it took to run this request
Sometimes on different platforms you need access to the original axios error that was thrown:
originalError - Error - the error that axios threw in case you need more info
you can change the URL your api is connectiong to.
api.setBaseURL('https://some.other.place.com/api/v100')
console.log(`omg i am now at ${api.getBaseURL()}`)
Once you've created your api, you're able to change HTTP requests by calling setHeader or setHeaders on the api. These stay with the api instance, so you can just set 'em and forget 'em.
api.setHeader('Authorization', 'the new token goes here')
api.setHeaders({
Authorization: 'token',
'X-Even-More': 'hawtness',
})
Monitors are functions you can attach to the API which will be called when any request is made. You can use it to do things like:
모니터는 promise가 해결되기 전에 실행된다. You get an early sneak peak at what will come back.
You cannot change anything, just look.
a sample monitor:
const naviMonitor = response => console.log('hey! listen! ', response)
api.addMonitor(naviMonitor)
Any exceptions that you trigger in your monitor will not affect the flow of the api request.
api.addMonitor(response => this.kaboom())
Internally, each monitor callback is surrounded by an oppressive try/catch block.
Remember.Safety first!
In addition to monitoring, you can change every request or response globally.
This can be useful if you would like to:
monitor랑 다르게 exception 처리를 해줘야 한다..
Unlike monitors, exceptions are not swallowed. They will bring down the stack, so be careful!
For responses, you're provided an object with these properties.
Data는 유일한 바꿀 수 있는 option이다.
api.addResponseTransform(response => {
const badluck = Math.floor(Math.random() * 10) === 0
if (badluck) {
// just mutate the data to what you want.
response.data.doorsOpen = false
response.data.message = 'I cannot let you do that.'
}
})
Or make it async:
api.addAsyncResponseTransform(async response => {
const something = await AsyncStorage.load('something')
if (something) {
// just mutate the data to what you want.
response.data.doorsOpen = false
response.data.message = 'I cannot let you do that.'
}
})
For requests, you are given a request object. Mutate anything in here to change anything about the request.
The object passed in has these properties:
Request transforms can be a function:
api.addRequestTransform(request => {
request.headers['X-Request-Transform'] = 'Changing Stuff!'
request.params['page'] = 42
delete request.params.secure
request.url = request.url.replace(/\/v1\//, '/v2/')
if (request.data.password && request.data.password === 'password') {
request.data.username = `${request.data.username} is secure!`
}
})
And you can also add an async version for use with Promises or async/await. When you reslove your promise, ensure you pass the request along.
api.addAsyncRequestTransform(request => {
return new Promise(resolve => setTimeout(resolve, 2000))
})
api.addAsyncRequestTransform(request => async () => {
await AsyncStorage.load('something')
})
This is great if you need to fetch an API key from storage for example.
Multiple async transforms will be run one at a time in successin, not parallel.
If you're more of a stage-0 kinda person, you can use it like this:
const api = create({ baseURL: '...' })
const response = await api.get('/slowest/site/on/the/net')
console.log(response.ok) // yay!
import { CancelToken } from 'apisauce'
const source = CancelToken.source()
const api = create({ baseURL: 'github.com' })
api.get('/users', {}, { cancelToken: source.token })
// To cancel request
source.cancel()
The problem property on responses is filled with the best guess on where the problem lies. You can use a switch to check the problem. The values are exposed as CONSTANTS hanging on your built API.
Constant VALUE Status Code Explanation
----------------------------------------------------------------------------------------
NONE null 200-299 No problems.
CLIENT_ERROR 'CLIENT_ERROR' 400-499 Any non-specific 400 series error.
SERVER_ERROR 'SERVER_ERROR' 500-599 Any 500 series error.
TIMEOUT_ERROR 'TIMEOUT_ERROR' --- Server didn't respond in time.
CONNECTION_ERROR 'CONNECTION_ERROR' --- Server not available, bad dns.
NETWORK_ERROR 'NETWORK_ERROR' --- Network not available.
CANCEL_ERROR 'CANCEL_ERROR' --- Request has been cancelled. Only possible if `cancelToken` is provided in config, see axios `Cancellation`.
Which problem is chosen will be picked by walking down the list.
A common testing pattern is to use axios-mock-adapter to mock axios and respond with stubbed data. These libraries mock a specific instance of axios, and don't globally intercept all instances of axios. When using a mocking library like this, it's important to make sure to pass the same axios instance into the mock adapter.
Here is an example code from axios_mock, modified to work with Apisauce:
import apisauce from 'apisauce'
import MockAdapter from 'axios-mock-adapter'
test('mock adapter', async () => {
const api = apisauce.create("https://api.github.com")
- const mock = new MockAdapter(axios)
+ const mock = new MockAdapter(api.axiosInstance)
mock.onGet("/repos/skellock/apisauce/commits").reply(200, {
commits: [{ id: 1, sha: "aef849923444" }], //hash 값으로 데이터 맞는지 확인
});
const response = await api..get('/repos/skellock/apisauce/commits')
expect(response.data[0].sha).toEqual"aef849923444")
})