Git Product home page Git Product logo

apisauce's Introduction

Apisauce

(Ring ring ring)
< Hello?
> Hi, can I speak to JSON API.
< Speaking.
> Hi, it's me JavaScript.  Look, we need to talk.
< Now is not a good time...
> Wait, I just wanted to say, sorry.
< ...

Talking to APIs doesn't have to be awkward anymore.

npm module

Features

  • low-fat wrapper for the amazing axios http client library
  • all responses follow the same flow: success and failure alike
  • responses have a problem property to help guide exception flow
  • attach functions that get called each request
  • attach functions that change all request or response data
  • detects connection issues (on React Native)

Installing

npm i apisauce --save or yarn add apisauce

  • Depends on axios.
  • Compatible with ES5.
  • Built with TypeScript.
  • Supports Node, the browser, and React Native.

Quick Start

// 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' } })

See the examples folder for more code.

Documentation

Create an API

You create an api by calling .create() and passing in a configuration object.

const api = create({ baseURL: 'https://api.github.com' })

The only required property is baseURL and it should be the starting point for your API. It can contain a sub-path and a port 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:

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 })

Calling The API

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:

  • url - the relative path to the API (required)
  • params - Object - query string variables (optional)
  • axiosConfig - Object - config passed along to the axios request (optional)

post, put, and patch accept 3 different parameters:

  • url - the relative path to the API (required)
  • data - Object - the object jumping the wire
  • axiosConfig - Object - config passed along to the axios request (optional)

any only accept one parameter

  • config - Object - config passed along to the axios request, this object same as axiosConfig

Responses

The responses are promise-based, so you'll need to handle things in a .then() function.

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 any 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

Changing Base URL

You can change the URL your api is connecting to.

api.setBaseURL('https://some.other.place.com/api/v100')
console.log(`omg i am now at ${api.getBaseURL()}`)

Changing Headers

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',
})

Adding Monitors

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:

  • check for headers and record values
  • determine if you need to trigger other parts of your code
  • measure performance of API calls
  • perform logging

Monitors are run just before the promise is resolved. You get an early sneak peak at what will come back.

You cannot change anything, just look.

Here's 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!

Adding Transforms

In addition to monitoring, you can change every request or response globally.

This can be useful if you would like to:

  • fix an api response
  • add/edit/delete query string variables for all requests
  • change outbound headers without changing everywhere in your app

Unlike monitors, exceptions are not swallowed. They will bring down the stack, so be careful!

Response Transforms

For responses, you're provided an object with these properties.

  • data - the object originally from the server that you might wanna mess with
  • duration - the number of milliseconds
  • problem - the problem code (see the bottom for the list)
  • ok - true or false
  • status - the HTTP status code
  • headers - the HTTP response headers
  • config - the underlying axios config for the request

Data is the only option changeable.

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.'
  }
})

Request Transforms

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:

  • data - the object being passed up to the server
  • method - the HTTP verb
  • url - the url we're hitting
  • headers - the request headers
  • params - the request params for get, delete, head, link, unlink

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 resolve 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 succession, not parallel.

Using Async/Await

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!

Cancel Request

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()

Problem Codes

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.

Mocking with axios-mock-adapter (or other libraries)

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" }],
  });

  const response = await api..get('/repos/skellock/apisauce/commits')
  expect(response.data[0].sha).toEqual"aef849923444")
})

Contributing

Bugs? Comments? Features? PRs and Issues happily welcomed! Make sure to check out our contributing guide to get started!

apisauce's People

Contributors

carlinisaacson avatar chakrihacker avatar cloud-walker avatar developius avatar dgobaud avatar dxiao avatar eithe avatar elvinra avatar gantman avatar hammadzz avatar i0x0 avatar jamonholmgren avatar jeremyadavis avatar jhpedemonte avatar jkeam avatar juddey avatar justim avatar max-lychko avatar mehulmpt avatar navneetccna avatar rdewolff avatar robinheinze avatar rollinrolanding avatar rszalski avatar ryanlntn avatar semantic-release-bot avatar silasjmatson avatar skellock avatar thestevemitchell avatar treeduship avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apisauce's Issues

Webpack bundle size and ramda redundance

My current apisauce version is 0.6 and I can't upgrade it for another issue that I will open later, maybe this issue is already solved..

This is the size of my main bundle external packages
screen shot 2017-03-16 at 08 35 46

As you may notice I have a problem with ramda.js, the library is first in terms of size, and I bet because I import the whole library without tree-shaking/picking only the functions I really use in the application..

But I also see a double ramda depedency coming from apisauce!

Document how to run tests

I tried running npm test using Node 6/NPM 3.8.9 and Node 4/ NPM 2.15.1 with no luck. Both complained about the import statements so I guess they were not being transpiled by babel.

When running Node 4 I also had to install babel-core and babel-plugin-transform-runtime because these were not part of the deps of the project.

Post request gives "GET" as response.data

Hi, I've been struggling with this for a while and can't seem to find a solution.

I am sending this request:

//Service
const postPasswordLogin = function (email, password, deviceId, deviceType) {
    var data = {email, password, deviceId, deviceType};
    return api.post('/sign-in/password', data);
  };
//Saga
const response = yield call(api.postPasswordLogin, email, password, 'alibaba', 'android');
console.log(response);

but I keep getting a response like this:

Object
config:Object
data:"GET"
duration:1177
headers:Object
ok:true
problem:null
status:200

if I test the API request with postman using the same JSON object as I see in config and with application/json headers, server responds just fine. With apisause it seems like it's attempting to send some kind of error (because response header is text/html instead of JSON), but such error won't have a 200 status code and definitely will have some response..

any ideas?

Set mode: no-cors

@skellock
How can I set the mode to no-cors?

In fetch I would do it this way:

fetch('https://github.com/', {
    method: 'get',
    headers: {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
    },
    mode: 'no-cors',
}))

How can I achieve similar thing with axios/apisauce

Thank you in advance.

Send body as string

We got some weird api which requires the body of the POST request to be a string like this
username=xyz&password=abc
And the content type has to be

I tried the following

const body = {username, password};
// and 
const body = `username=xyz&password=abc`;
const options = {
    headers: {
        'Accept'      : 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded'
    }
};
return this.api.post('/tokenAuthentication/getToken.json', body, options);

In both cases it didn't worked. How do i send a request with just a string?

Request body broken

Not sure if I'm missing something simple or not.
When I send a POST request that has two or more parameters the request is rejected.

The request body for a successful request usually looks like this:
{ email: '[email protected]', password: 'xxxxxx' }

but instead I get this:
{ '{"email":"[email protected]","password":"xxxxxx"}': '' }

If I have only one parameter it works fine.
Using in a react native app made with the infinitered/ignite generator.

Setting Default Headers After Create

You can set the default headers when you call create(). Yay.

But if you want to change that after that call, you have to reach into the axiosInstance.defaults.headers object to mutate it.

Let's provide a nicer way for this.

Avoiding ssl cert verification

I'm using apisauce in React Native app to connect to an external api that is not on my own.
I'm working with a dev environment that i cannot touch and i would like to ignore the cert error to test the connection.
There is a way to ignore invalid certificates?

timeout

Supposedly awaiting features in 0.25, I know you were planning on doing timout in constructor.

It appears they've added an onTimeout. Would be a good add-on to assure this works with API sauce and associated docs.

asynchronous transformers

a server i'm communicating with requires a signature to be generated from a key-pair and appended as a header for every request. i decided to try and use a request transformer to keep this signature generating code in one place, instead of passing a signature value in with every api.whatever('/where/ever') call.

the module i'm using for generating these signatures works exclusively with promises. as a result of this constraint, i have tried these two approaches:

// approach one
api.addRequestTransform(async function(request) {
    var now = crypto.createHash('sha256').update(Date.now()).digest()
    request.headers['x-message'] = now.toString('hex')
    request.headers['x-signature'] = await sign(Buffer.from(privatekey, 'hex'), now)
})
// approach two
api.addRequestTransform(function(request) {
    var now = crypto.createHash('sha256').update(Date.now()).digest()
    request.headers['x-message'] = now.toString('hex')
    sign(Buffer.from(privatekey, 'hex'), now).then(function(sig) {
        request.headers['x-signature'] = sig.toString('hex')
    }).catch(function(err) {
        // abort the request, somehow
    })
})

when the request is fired, the value that i attempted to set in the transformer is not present. after reading the request transformer part of the source code, it appears to be attributed to ramda foreach not waiting for my promise to resolve.

so, is it okay to be using asynchronous functions within a transformer? (i'm presuming the answer is no 😄 ) or should i try and find a way to generate these signatures synchronously?

edit:
is it possible to support asynchronous transformers? if so, any pointers for implementing? i'd be happy to have a crack at it!

Hi, I want to help to continue using your package

Hi @skellock, I'm a front-end dev from Wanderio and I'm using your package since this summer.

I find your package really useful to isolate the API calls of my application, so I wish to continue use it.

But recently I had some trouble with it, so I will try to help you!

I will open some issues about each topic so we can tackle them separately, thanks in advance!

camelize keys

Cannot do this in a transform:

response.data = camelizeKeys(response.data);

use request transformers to abort request if condition unmet

it would be nice if we can setup a transformer that can intercept a request and delay its execution until some condition is met.

in my case i'm using api-sauce in an react-native app. i want to intercept any api call IF user is not online and either cancel it. or delay its execution;

i tried returning rejected promise in requestTransformer but it doesnot work

const api = apisauce.create({
  baseURL,
  headers: header,
  timeout: 20000,
});
api.addRequestTransform((request) => {
  if(!Config.isOnline()) {
    return new Promise((ok, not)=>not({ok: false, data: {message: 'Your device is not connected to internet'}, status: 412}));
  } else {
    return request;
  }
});

is there another method to reject request before sending it if some condition is unmet ?
it would be very nice also if we can keep the request pending until device is back on the resolve promise :).

thanks

Dealing With Null Parameters

The QSV parsing is taking objects that are null and transforming them into the string "null". That's not cool.

api.addAsyncRequestTransform is not a function error

const api = apisauce.create({
    // base URL is read from the "constructor"
    baseURL,
    // here are some default headers
    headers: {
      'Cache-Control': 'no-cache'
    },
    // 10 second timeout...
    timeout: 10000
  })

api.addAsyncRequestTransform(request => async () => {
    request.headers['Authorization'] = 'Bearer ' + await AsyncStorage.getItem('@nytevibetoken');
  });

throwing api.addAsyncRequestTransform is not a function error. Why? I want to fethc token from AsyncStorage and add it o header. Any suggestion?

add transform to GET

Docs clearly say PUT/POST/PATCH gets addRequestTransform but I could sure use it for a GET. Any reason it's not supported?

If philosophically, then let's discuss.

If just not done yet, then I'd love to add it!

Upload progress handler for post requests

For a post request it would be a great feature to be able to see the upload progress. Attaching some kind of handler to a request seems like the right way to do it: (progressValue) => do stuff
api.post('url', data, (progressValue) => do stuff)

From the Axios docs:

// onUploadProgress allows handling of progress events for uploads
onUploadProgress: function (progressEvent) { // Do whatever you want with the native progress event }

204 response with ok false on Android

So, I'm not sure you are gonna be able to reproduce it. But I think its worth I mention this bug.
react native v. 0.33.1
axios v. 0.8.0

In a simple POST, Im getting back a ok with False, in a 204 (no content) response.

Now the tricky part:
It only happen on Android in production.
It didn't happen on iOS (prod or dev), neither on Android in development mode (emulator and device).
During the local tests, I was pointing to the production environment.

Any ideia what might cause that?

Timeout not being detected

Good day,

I'm not getting a timeout on an IP address that does not exist. Rather the app is waiting for a NETWORK_ERROR which can take a lot longer (several minutes in some circumstances). My setup below:

    const api = apisauce.create({
        // base URL is read from the "constructor"
        baseURL,
        // here are some default headers
        headers: {
            'Cache-Control': 'no-cache'
        },
        // 10 second timeout...
        timeout: 2000
    })

const testURL = () => api.get('/');

const result = yield call(api.testURL);

OR

api.testURL().then(
    (result) => console.warn(result),
    (err) => console.error(err)
  )

Regards

Find a different way to async/await

The latest version just added 7 MB on to size because of the babel-runtime dependency. That's crazy. Find a different way to do that. There's a handful of transformers out there that don't have a dependency on babel-runtime.

testing and mocking apisauce examples

Hello

We have recently investigating React Native for cross-platform mobile development and been using this awesome library. I am in the point of investigating unit testing and trying to mock the async of apisauce in my Redux's Actions.

I followed the recommended approach in Redux Writing Test documentation here with no success. My JS is level is pretty beginner and was wondering if anyone using this library can share what you did for testing/mocking Actions in Redux.

weird "NETWORK_ERROR" while connect to my server

I was following the infiniteRed/ignite way to making api calls by using redux / redux-saga

but I got wired "NETWORK_ERROR" when I was trying to make api call to my sever on AWS even on localhost.
but under the same network condition, I replaced the baseURL to the github demo one, which works just fine (returning some 'CLIENT_ERROR' since I was calling the non-exist endpoint)

this is what I logged response:
Object {duration: 246, problem: "NETWORK_ERROR", ok: false, status: null, headers: null…}
config
:
null
data
:
null
duration
:
246
headers
:
null
ok
:
false
problem
:
"NETWORK_ERROR"
status
:
null

does someone have any insight about this? and I noticed that '[NEW] Network errors and timeouts are now detected on React Native - @skellock' on 0.2.0 release, then I upgrade apisuace to 0.3.0, but the error happens - -

Got error unresolved

after i installed the apisauce i got error:

transformed 416/417 (100%)(node:2216) UnhandledPromiseRejectionWarning: Unhandle
d promise rejection (rejection id: 290): UnableToResolveError: Unable to resolve
module http from F:\ReactNative\test\node_modules\axios\lib\adapters\http.js: M
odule does not exist in the module map or in these directories:
F:\ReactNative\test\node_modules

i work with windows 7, npm and android
the files exists in the directory...

Undefined only on android

When i try to fetch anything from my api i get the following error in pidcat: [TypeError: undefined is not an object (evaluating 'error.response.status')]. In your source is only one place with error.response.status

var getProblemFromError = function getProblemFromError(error) {
    // first check if the error message is Network Error (set by axios at 0.12) on platforms other than NodeJS.
    if (error.message === 'Network Error') return NETWORK_ERROR;
    // then check the specific error code
    return R.cond([
    // if we don't have an error code, we have a response status
    [R.isNil, function () {
      return getProblemFromStatus(error.response.status);
    }], [R.contains(R.__, TIMEOUT_ERROR_CODES), R.always(TIMEOUT_ERROR)], [R.contains(R.__, NODEJS_CONNECTION_ERROR_CODES), R.always(CONNECTION_ERROR)], [R.T, R.always(UNKNOWN_ERROR)]])(error.code);
  };

Do you know what my problem is and what i'am doing wrong?

I use this commit 7aa56ac and rn 0.32.0

Error Message Detection on React Native

So, turns out, this is not straight forward.

axios uses XmlHttpRequest which uses JavaScriptCore which is different for each platform.

I tested on a few devices: iOS 8.1, 8.2, 8.3, 9.0, 9.1, 9.3 and Android 16, 22.

I tested a few scenarios (bad dns, ssh port, no port, no server, fast time, slow time).

It's all over the map.

XmlHttpRequest Responses

--- DNS ---
android 16 - Unable to resolve host "kelsdfjhklasjf": No address associated with hostname
ios 8.3 - A server with the specified hostname could not be found.
iOS 8.2 - The operation couldn’t be completed. (NSURLErrorDomain error -1003.)

--- Couldn’t connect ---
iOS 9 - Could not connect to the server.
iOS 8.2 - The operation couldn’t be completed. (NSURLErrorDomain error -1004.)
android 22 - failed to connect (SECRET DATA GOES HERE): connect failed: ECONNREFUSED (Connection refused)'

--- Time out ---
iOS 8.1 The operation couldn’t be completed. (NSURLErrorDomain error -1001.)
iOS 8.2 The operation couldn’t be completed. (NSURLErrorDomain error -1001.)
iOS 8.3 The request timed out.
android 22 - SSL handshake timed out
android 22 - timeout
android 16 - Read timed out


--- Bad Port ---
iOS 8.1 - The operation couldn’t be completed. (NSURLErrorDomain error -1005.)
iOS 8.2 - The operation couldn’t be completed. (NSURLErrorDomain error -1005.)
iOS 8.3 - The network connection was lost.
iOS 9.3 - The network connection was lost.
android 22 - Unexpected status line: SSH-2.0-OpenSSH_6.0p1 Debian-3ubuntu1.2

I'm thinking there should be a ghetto mode detection with all of this stuff in it.

Off by default? I'm not sure.

Middleware feature

Is it possible to implement a middleware feature like the addMonitor method? Like if i want to handle every response in a certain way. Now i have to add to every request a .then

response with status 400 resolved successfully instead of rejected

"apisauce": "0.6.0"

api.post('/oauth/token', data)
   .then((res) => console.log(res));

the below response is logged in "then"

{
    "duration":190,
    "problem":"CLIENT_ERROR",
    "ok":false,
    "status":400,
    "headers":{
        "content-type":"application/json;charset=UTF-8",
        "access-control-allow-origin":"",
        "pragma":"no-cache, no-cache",
        "x-xss-protection":"1; mode=block",
        "transfer-encoding":"Identity",
        "access-control-max-age":"3600",
        "expires":"0",
        "cache-control":"no-cache, no-store, max-age=0, must-revalidate, no-store",
        "date":"Mon, 23 Jan 2017 23:37:54 GMT",
        "access-control-allow-credentials":"true",
        "x-content-type-options":"nosniff",
        "vary":"Accept-Encoding",
        "x-frame-options":"DENY"
    },
    "config":{
        "transformRequest":{

        },
        "transformResponse":{

        },
        "headers":{
            "Accept":"application/json",
            "Content-Type":"application/json",
        },
        "timeout":0,
        "xsrfCookieName":"XSRF-TOKEN",
        "xsrfHeaderName":"X-XSRF-TOKEN",
        "maxContentLength":-1,
        "baseURL":"http://114.119.116.135:8000/fe-oauth",
        "method":"post",
        "url":"http://localhost:8000/oauth/token",
        "data":"{\"grant_type\":\"password\"}"
    },
    "data":{
        "error":"invalid_request",
        "error_description":"Missing grant type"
    }
}

Function that returns a promise, to return response.

I'm not terribly sure if I'm missing something basic. This could just be my ignorance.

I want to do something special when login api is called. It should do something with response, then return the promise. But it appears to swallow response

Ergo:

api
  .post('/repos/skellock/apisauce/commits')
  .then((response) => response.data[0].commit.message)
  .then((response) => window.alert(response.data.taco))

second promise is like "WUT? WUTs this response thing yo?"

This is critical, because I want a certain API function to update headers, but not to keep response away from the following paths the promise might be handed. I hope I made this clear... I need coffee ☕

Axios auth config not exposed in apisouce

I want to set basic auth on axios requests using its auth config property. Username and password (used for basic auth) is not know at the time of creation so it can't be set then. What is the solution so that I don't have to set the Authorization header myself?

Parallel request (?)

Hi @skellock ,
I'm facing an issue when i am fetching on first request and then fetching second request. its look like the second request is waiting for the first to be done. The second request is being called on another route. Imagine if you are on products page and currently fetching each product's price and then you press one of product and will be redirected into new page (product detail page). on the new page, you create another request to get product's detail data. Any idea about this?

Upgrading to 0.10 breaks chrome 34

This is the error
screen shot 2017-03-16 at 08 53 03

And I think the bug come from regenerator-runtime dependency used by the package to support async/await.

I'm not sure which is the best solution:

  • try to use another solution to support async/await (fast-async? As you already mentioned on #58 ?)
  • maybe I should simply polyfill the symbol.toStringTag thing?
  • we should open an issue on the regenerator-runtime package?

Idea: A nicer way for pre check an url before firing a request

For my app i want to implement an asyncStorage cache. Right now i temporary save your get method, replace it with my own and call the saved get method inside my own.

How about you add something like the request transformer just for pre checking a request? This is just an idea. If you don't like it just close the issue :)

this.request = create({
 baseURL: url || 'http://localhost',
 headers: {
  'Accept'   : 'application/json',
  'Content-Type': 'application/json'
 }
});

const originalGet = this.request.get;

this.request.get = (url, params = {}) => {
 return new Promise(resolve=> {
  const key = buildURL(url, params);

  AsyncStorage.getItem(key, (error, value)=> {
   if (!error && value) {

    const data = JSON.parse(value);
    if (moment(data.expires) >= moment()) {
     console.log(`[CACHED_GET] ${url} ${JSON.stringify(params)}`);
     return resolve({ok: true, fromCache: true, data: data.data});
    }
   }

   return resolve(originalGet(url, params));
  });
 })
};

this.request.addResponseTransform((response)=> {
 if (response.ok) {
  const url = response.config.url.replace(response.config.baseURL, '');
  var params = response.config.params;
  delete params.api_key;

  const key = '/' + buildURL(url, params);

  const data = {
   expires: moment().add(7, 'days').toDate().getTime(),
   data   : response.data
  };

  console.log(`[SAVE_GET] ${url} ${JSON.stringify(params)}`);

  AsyncStorage.setItem(key, JSON.stringify(data));
 }
});

Response transformers don't change the data

I cannot change the data anymore within a response transformer.

api.addResponseTransform((response)=> {  
  response.data = { ... }
});

api.get('user').then(response=>{
  console.log(response.data); // the original data from my api
})

Is it possible that the transformer api has changed?

EDIT: ok my cleanup function has changed. Before i have done something like this

API.request.addResponseTransform((response)=> {
    if ( response.ok ) {
        HydraCleanUp(response.data);
    }
});

HydraCleanUp mutated the data inside the response.data object;

Now i have this code

API.request.addResponseTransform((response)=> {
    if ( response.ok ) {
        const data = HydraCleanUp(response.data);
       response.data = data;
    }
});

And this does not work because i would assign another reference to response.data;

Logging Functionality

It doesn't need to be a monitor, but maybe just a way to turn on console.logging.

Maybe also have levels like: none, simple, grouping.

Where grouping will use the grouping functionality in chrome debugging.

post with form-data

Hi,

I am having difficulty passing multiple variables to the post method using apisauce.
I am getting a response with data.error which indicates that it didn't receive the params

import apisauce from 'apisauce'

const create = (baseURL = 'http://prod.karma.vote/api/') => {
	const api = apisauce.create({
    	baseURL,
    	headers: {
    		'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8',
    		'Accept' : '*/*'
    	}
  	})

  	if (__DEV__ && console.tron) {
    	api.addMonitor(console.tron.apisauce)
  	}


  	const login = () => {
  		return api.post('login', {
        {
    			email: '[email protected]',  firstName: 'XX', 
    			lastName: 'XX',  profilePicUrl: 'example.png',
    			'device.facebookId': '1234567', 'device.token': '',
  			 'device.platform': ''
        });
    
  	}

	return {
		login
	}
}

export default {
  create
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.