Coder Social home page Coder Social logo

purest's Introduction

Purest

npm-version travis-ci coveralls-status codecov-status

Purest is a thin wrapper around the request module, adding expressive API and extensive configuration data structure to ensure seamless communication with any REST API provider in a consistent and straightforward way:

var Purest = require('purest')
  , google = new Purest({provider:'google'})

google.query('youtube')
  .select('channels')
  .where({forUsername:'RayWilliamJohnson'})
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

Table of Contents

Quick Start

var Purest = require('purest')
var google = new Purest({provider:'google'})

google.get('channels', {
  api:'youtube',
  auth:{bearer:'[ACCESS_TOKEN]'},
  qs:{forUsername:'RayWilliamJohnson'}
}, function (err, res, body) {})

In this example we are requesting the channels endpoint of the YouTube API. Here is how the related portion of the Google's configuration in config/providers.json looks like:

"google": {
  "https://www.googleapis.com": {
    "__domain": {
      "auth": {
        "auth": {"bearer": "[0]"}
      }
    },
    "{endpoint}": {
      "__path": {
        "alias": "__default"
      }
    },
    "youtube/[version]/{endpoint}": {
      "__path": {
        "alias": "youtube",
        "version": "v3"
      }
    }
  }
}

Using the above configuration Purest knows how to construct the absolute URL https://www.googleapis.com/youtube/v3/channels for the channels endpoint.

Given the above configuration you can use the so called __default path as well:

google.get('youtube/v3/channels', {
  auth:{bearer:'[ACCESS_TOKEN]'},
  qs:{forUsername:'RayWilliamJohnson'}
}, function (err, res, body) {})

Notice that when using the __default path, specifying a path alias through the api key is no longer needed.

Or even the absolute URL:

google.get('https://www.googleapis.com/youtube/v3/channels', {
  auth:{bearer:'[ACCESS_TOKEN]'},
  qs:{forUsername:'RayWilliamJohnson'}
}, function (err, res, body) {})

The underlying request module is accessible as well:

var Purest = require('purest')
Purest.request(...)

You can create a separate instance specifically for making requests to the YouTube API:

var youtube = new Purest({provider:'google', api:'youtube'})

youtube.get('channels', {
  auth:{bearer:'[ACCESS_TOKEN]'},
  qs:{forUsername:'RayWilliamJohnson'}
}, function (err, res, body) {})

Notice that specifying api:'youtube' for each request is no longer required.

A more expressive Query API is available as well:

var google = new Purest({provider:'google'})
google.query('youtube')
  .select('channels')
  .where({forUsername:'RayWilliamJohnson'})
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})
// OR
var youtube = new Purest({provider:'google', api:'youtube'})
youtube.query()
  .select('channels')
  .where({forUsername:'RayWilliamJohnson'})
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

Using the .query() method without arguments means using the __default path defined for that provider.

If you're going to make authenticated requests on behalf of a single user, you can use the request's defaults to set the access token to use for each request made through that instance:

var youtube = new Purest({
  provider:'google', api:'youtube',
  defaults:{auth:{bearer:'[ACCESS_TOKEN]'}}
})
// then just
youtube.query()
  .select('channels')
  .where({forUsername:'RayWilliamJohnson'})
  .request(function (err, res, body) {})

Constructor

The Purest's constructor accepts a couple of options, with only the provider option being required:

var google = new Purest({provider:'google'})
Provider

Alternatively this can be a any custom name, in case a custom provider is being defined through the config option (see below).

OAuth 1.0
  • key - consumer_key to use for all requests
  • secret - consumer_secret to use for all requests

These keys are just convenience shortcuts, as it's often required to make all of the requests through a single OAuth1.0 app, and specifying these values for each request can be irritating.

Both key and secret can be overridden for each request through the regular oauth option. Alternatively these values can be set throught the defaults option as well:
{oauth:{consumer_key:'..', consumer_secret:'..'}}.

Path Alias (API)
  • api - set specific API/alias path to use for all requests

The api key can be overridden for each request as well.

URL Modifiers
  • subdomain - set default value to replace the [subdomain] URL token with
  • subpath - set default value to replace the [subpath] URL token with
  • version - set default value to replace the [version] URL token with
  • type - set default value to replace the [type] URL token with

All of these keys can be overridden per request as well. Take a look at the URL Modifiers section for more details.

Configuration

See the Create New Provider and the Extend Existing Provider sections.

These values are appended to the request's options right before the request starts, meaning that they override any other previously defined options in Purest.

  • before - object containing functions to execute before all or certain HTTP verb requests.

See the Before Request Hooks section for more details.

See the Query Method Aliases section for more details.

  • promise - set to true to promisify the underlying request module used by Purest.

The bluebird module used internally by Purest should be installed first: $ npm install bluebird
Take a look at the Promises Documentation and the Promises Examples.

The request-debug module should be installed first: $ npm install request-debug

Basic API

The basic API resembles the one found in the request module:

[purest instance].[http method](
  'endpoint',
  {mikeal's request options + some specific to purest},
  callback([error object], [response object], [parsed JSON body])
)

The first argument is the {endpoint} you want to be replaced in the currently matched path of your provider configuration.

The second argument is the request's options that you normally pass to the request module + a few more specific to Purest.

The third argument is the regular request's callback function. These are the callback arguments (pasted from the request's docs):

  1. An error when applicable (usually from http.ClientRequest object)
  1. An http.IncomingMessage object
  2. The third is the response body (String or Buffer, or JSON object if the json option is supplied)

Purest sets json:true for all of your requests by default, so body is always a parsed JSON object.

Query API

Purest provides convenient API to make your application code more expressive:

var Purest = require('purest')
var google = new Purest({provider:'google'})

google.query('youtube')
  .select('channels')
  .where({forUsername:'RayWilliamJohnson'})
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

There are a couple of method aliases pre-defined for you in config/query.json:

{
  "verbs": {
    "get"      : ["select", "read"],
    "post"     : ["update", "send", "submit"],
    "put"      : ["create", "insert", "write"],
    ...
  },
  "options": {
    "qs"       : ["where"],
    "form"     : ["set"],
    "formData" : ["upload"],
    "headers"  : [],
    ...
    "options"  : []
  },
  "custom": {
    "auth"     : [],
    "request"  : []
  }
}

The actual methods are on the left and their aliases are to the right. You can define your own method aliases and use them instead.

The verbs key contains all HTTP verbs. options contains methods used to pass any valid option to the underlying request module.

The .options() method from this section can be used to pass any valid option to the underlying request module, even if there isn't explicitly defined query method for it.

Lastly the custom section contains methods specific to Purest.

Query and Request

Each query starts with the .query() method and ends with the .request() method:

// var google = new Purest({provider:'google'})
google
  .query()
  // ... other query methods
  .request()

Using the .query() method without parameters results in using the __default path from that provider's configuration.

To use a specific API/alias path from that provider, you can pass the alias name to the .query() method:

// var google = new Purest({provider:'google'})
google
  .query('youtube')
  // ... other query methods
  .request()

Alternatively the API/alias name can be passed using the Purest's specific api key and the generic .options() method of the Query API:

// var google = new Purest({provider:'google'})
google
  .query()
  .options({api:'youtube'})
  // ... other query methods
  .request()

The .request([callback]) method returns the underlying request object, so streaming works as usual. The callback is the same you'll find in request.

Additionally Purest passes json:true by default to each request, so the response body is always a parsed JSON object:

// var google = new Purest({provider:'google'})
google
  .query()
  // .options({json:true}) // not needed
  .request(function (err, res, body) {
    // body is a parsed JSON object
  })

Authentication

The .auth() method is used to abstract out the authentication related parameters that you have to pass to each request:

// var google = new Purest({provider:'google'})
google.query()
  .auth('[ACCESS_TOKEN]')
  .request()

And this is how the related portion of the Google's configuration looks like:

"google": {
  "https://www.googleapis.com": {
    "__domain": {
      "auth": {
        "auth": {"bearer": "[0]"}
      }
    }
  }
}

Alternatively you can use:

// var google = new Purest({provider:'google'})
google.query()
  .auth({bearer:'[ACCESS_TOKEN]'})
  .request()
// OR
google.query()
  .options({auth:{bearer:'[ACCESS_TOKEN]'}})
  .request()

Notice that if you pass an object to the .auth({}) method, Purest sets the regular auth option found in request.

Take a look at the Auth section of the Provider Configuration chapter on how to configure the .auth() method.

Alternatively you can search for "auth" in config/providers.json to see how various auth schemes are configured.

Provider Configuration

This is how Facebook is configured in config/providers.json:

"facebook": {
  "https://graph.facebook.com": {
    "__domain": {
      "auth": {
        "auth": {"bearer": "[0]"}
      }
    },
    "{endpoint}": {
      "__path": {
        "alias": "__default"
      }
    }
  }
}

That's about the bare minimum configuration you want to have for a provider.

With that configuration you can request the user's profile like this:

// var facebook = new Purest({provider:'facebook'})
facebook.query()
  .get('me')
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

This will result in requesting the https://graph.facebook.com/me endpoint. Purest will also send the Authorization: Bearer [ACCESS_TOKEN] header for you.

Domain

Each provider configuration should contain at least one domain in it:

"google": {
  "https://www.googleapis.com": {...},
  "https://maps.googleapis.com": {...},
  "https://www.google.com": {...},
  "https://accounts.google.com": {...}
}

Each domain can have a __domain meta key, containing specific options for that domain:

"https://graph.facebook.com": {
  "__domain": {
    "auth": {
      "auth": {"bearer": "[0]"}
    }
  }
}

In this case we're specifying authentication scheme to use with the .auth() method of the Query API.

Auth

The auth key can be placed inside __domain, __path or __endpoint meta key. The innermost auth configuration overrides the outer ones.

The auth key is designed to be used only with the .auth() method of the Query API. It can contain any request option used for authentication:

// Example: (one of the following)
"auth": {
  // OAuth1.0
  "oauth": {"token": "[0]", "secret": "[1]"}
  // OAuth2 header
  "auth": {"bearer": "[0]"}
  // basic auth
  "auth": {"user": "[0]", "pass": "[1]"}
  // custom header
  "headers": {"Authorize": "X-Shopify-Access-Token [0]"}
  // querystring
  "qs": {"access_token": "[0]"}
  // querystring
  "qs": {"api_key": "[0]", "api_secret": "[1]"}
  // combination of querystring + header
  "qs": {"client_id": "[0]"}, "headers": {"Authorization": "OAuth [1]"}
}

Having such configuration you can pass just the string values to the .auth() method:

// var facebook = new Purest({provider:'facebook'})
facebook.query()
  .get('me')
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

Alternatively the auth key can be an array of authentication schemes:

"auth": [
  {"auth": {"bearer": "[0]"}},
  {"auth": {"user": "[0]", "pass": "[1]"}}
]

With this configuration Purest will pick the authentication scheme based on the count of the parameters you are passing to the auth method:

// use OAuth2 Bearer header
facebook.query().auth('[ACCESS_TOKEN]')
// use Basic authentication
facebook.query().auth('[USER]', '[PASS]')

Path

Each domain can have multiple paths in it:

"google": {
  "https://www.googleapis.com": {
    "__domain": {
      "auth": {
        "auth": {"bearer": "[0]"}
      }
    },
    "{endpoint}": {
      "__path": {
        "alias": "__default"
      }
    },
    "plus/[version]/{endpoint}": {
      "__path": {
        "alias": "plus",
        "version": "v1"
      }
    },
    "youtube/[version]/{endpoint}": {
      "__path": {
        "alias": "youtube",
        "version": "v3"
      }
    }
  }
}

With the above configuration you can use the path aliases defined for the Google+ and the YouTube API to remove the clutter:

// var google = new Purest({provider:'google'})
google.query('youtube')
  .get('channels')
  .qs({mine:true})
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

This will result in requesting the https://www.googleapis.com/youtube/v3/channels endpoint from the YouTube API.

In the same way you can request the https://www.googleapis.com/plus/v1/people/me endpoint from the Google+ API:

google.query('plus')
  .select('people/me')
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

All available options for the __path key, can be found in the Path Modifiers section.

Alias

Each path should have a __path meta key in it containing alias to use to access that path (otherwise it won't be accessible):

"google": {
  "https://www.googleapis.com": {
    "plus/[version]/{endpoint}": {
      "__path": {
        "alias": "plus",
        "version": "v1"
      }
    }
  }
}

Having the above configuration you can access the Google+ API in various ways:

// Example: (one of the following)
// Set it for the entire provider instance
var google = new Purest({provider:'google', api:'plus'})
// Use it with the Basic API
google.get('people/me', {api:'plus'}, function (err, res, body) {})
// Use it with the Query API
google.query('plus').get('people/me').request(function (err, res, body) {})
// OR
google.query().get('people/me').options({api:'plus'}).request(function(err,res,body){})

Alternatively the alias configuration can contain array of names:

"google": {
  "https://www.googleapis.com": {
    "drive/[version]/{endpoint}": {
      "__path": {
        "alias": ["drive", "storage"],
        "version": "v2"
      }
    }
  }
}

With this configuration you can use either one of the specified aliases:

google.query('drive')
  .get('about')
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})
// same as
google.query('storage')
  .get('about')
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

Endpoint

Each path can have multiple endpoints defined in it. They are used to set specific options per endpoint:

"live": {
  "https://apis.live.net": {
    "__domain": {
      "auth": {
        "auth": {"bearer": "[0]"}
      }
    },
    "[version]/{endpoint}": {
      "__path": {
        "alias": "__default",
        "version": "v5.0"
      },
      "me/picture": {
        "get": {
          "encoding": null
        }
      },
      ".*\\/skydrive\\/files\\/.*": {
        "__endpoint": {
          "regex": true
        },
        "put": {
          "headers": {
            "Content-Type": "application/json"
          }
        }
      }
    }
  }
}

With the above configuration each GET request to the me/picture endpoint will have the encoding:null request option set:

// var live = new Purest({provider:'live'})
live.query()
  .get('me/picture')
  // no longer needed to set this option explicitly
  // .options({encoding:null})
  .request(function (err, res, body) {})

The encoding:null option is required when you expect binary response body, such as image.

Additionally, with the above configuration, each PUT request made to the [USER_ID]/skydrive/files/[FILE_NAME] endpoint will have its Content-Type: application/json header set.

The difference here is that this a regex endpoint, that should be defined as such:

".*\\/skydrive\\/files\\/.*": {
  "__endpoint": {
    "regex": true
  }
}

Omitting the regex:true key will result in a regular string endpoint.

Notice the double escape used in the regex string: .*\\/skydrive\\/files\\/.*

Match All

There is one special endpoint that can be used to match all endpoints:

"*": {
  "get": {
    "headers": {"x-li-format": "json"}
  }
}

This will result in all GET requests made to any of the endpoints in that path having the x-li-format: json header set.

Finally one specific HTTP verb can be used to match all request types as well:

"*": {
  "all": {
    "headers": {"x-li-format": "json"}
  }
}

This will result in having the x-li-format: json header being set always for that path.

URL Modifiers

Purest supports a few tokens that you can embed into your provider's domain and path configurations.

Domain Modifiers

There is only one domain modifier that you can use - [subdomain]:

"mailchimp": {
  "https://[subdomain].api.mailchimp.com": {...}
},
"salesforce": {
  "https://[subdomain].salesforce.com": {...}
}

The subdomain value is usually a user specific data that needs to be added to the domain dynamically.

You have a couple of options to set this value:

// Set it directly in the config
"salesforce": {
  "https://[subdomain].salesforce.com": {
    "__domain": {
      "subdomain": "us2"
    }
  }
}

// Set it in the constructor
var salesforce = new Purest({provider:'salesforce', subdomain:'us2'})

// Set it on each request
salesforce.get('me', {subdomain:'us2'}, function (err, res, body) {})
// OR
salesforce.query()
  .get('me')
  .options({subdomain:'us2'})
  .request(function (err, res, body) {})

Path Modifiers

The path modifiers are tokens that you can embed when defining a path in your configuration:

"basecamp": {
  "https://basecamp.com": {
    "[subpath]/api/[version]/{endpoint}.[type]": {
      "__path": {
        "alias": "__default",
        "version": "v1"
      }
    }
  }
}

Having the above configuration we can request the https://basecamp.com/123/api/v1/people/me.json endpoint like this:

// var basecamp = new Purest({provider:'basecamp'})
basecamp.query()
  .select('people/me')
  .options({subpath:'[USER_ID]'})
  .request(function (err, res, body) {})

Supported path modifiers:

  • [subpath] arbitrary string replaced in your path
  • [version] contains the version string
  • [type] defaults to json
  • {endpoint} the endpoint you are requesting. Notice the {}

You can set either one of this path modifiers in various ways (except the {endpoint} one):

// Set it directly in the config
"basecamp": {
  "https://basecamp.com": {
    "[subpath]/api/[version]/{endpoint}.[type]": {
      "__path": {
        "alias": "__default",
        "subpath": "some default value",
        "version": "v1",
        "type": "xml"
      }
    }
  }
}

// Set it in the constructor
var basecamp = new Purest({provider:'basecamp',
  subpath:'123', version:'v1.1', type:'xml'})

// Set it on each request
basecamp.get('me', {
  subpath:'123', version:'v1.1', type:'xml'
}, function (err, res, body) {})
// OR
basecamp.query()
  .get('me')
  .options({subpath:'456', version:'v1.2', type:'xml'})
  .request(function (err, res, body) {})

Create New Provider

You can create your own provider configuration and add it to the available providers through the config option of the Purest's constructor:

var awesome = new Purest({
  provider:'awesome',
  config:{
    "awesome":{
      "https://api.awesome.com":{
        "__domain":{
          "auth":{
            "auth":{"bearer": "[0]"}
          }
        },
        "[version]/{endpoint}.[type]":{
          "alias": "__default",
          "version": "1"
        }
      }
    }
  }
})

Then you can use the awesome provider as usual:

awesome.query()
  .get('some/endpoint')
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

All available provider configuration options can be found in the Provider Configuration section.

Extend Existing Provider

If you have the following configuration for Google in the config/providers.json file:

"google": {
  "https://www.googleapis.com": {
    "__domain": {
      "auth": {
        "auth": {"bearer": "[0]"}
      }
    },
    "{endpoint}": {
      "__path": {
        "alias": "__default"
      }
    }
  }
}

You can extend it through the config options of the Purest's constructor:

var google = new Purest({
  provider:'google',
  config:{
    "google": {
      "https://www.googleapis.com": {
        "youtube/[version]/{endpoint}": {
          "__path": {
            "alias": "youtube",
            "version": "v3"
          }
        },
        "drive/[version]/{endpoint}": {
          "__path": {
            "alias": "drive",
            "version": "v2"
          }
        }
      },
      "https://maps.googleapis.com":{...}
    }
  }
})

This will add two additional path aliases for the https://www.googleapis.com domain, and one additional domain - https://maps.googleapis.com.

All available provider configuration options can be found in the Provider Configuration section.

Before Request Hooks

Purest's extensive configuration data structure allows you to configure almost anything without the need to write a single line of code. However small bits of application logic may be required to get a fully compatible REST API client library for your provider:

var mailchimp = new Purest({
  provider:'mailchimp',
  before:{
    all: function (endpoint, options, config) {
      var dc = options.subdomain||this.subdomain||config.subdomain
      if (dc) return

      // extract data center name from apikey
      if (options.qs && /.*-\w{2}\d+/.test(options.qs.apikey)) {
        var dc = options.qs.apikey.replace(/.*-(\w{2}\d+)/, '$1')
        options.subdomain = dc
      }
    }
  }
})

The above function is executed before each request, and its sole purpose is to extract the user's data center name from the apikey querystring parameter passed to the request.

Mailchimp needs a correct data center name to be embedded into the API domain through the subdomain modifier:

"mailchimp": {
  "https://[subdomain].api.mailchimp.com": {...}}

Hook Structure

You can define HTTP hook for every valid HTTP verb + one special all hook to match all HTTP verbs:

var before = {
  all: function (endpoint, options, config) {},
  get: function (endpoint, options, config) {},
  post: function (endpoint, options, config) {}
}

Arguments:

  • endpoint - the endpoint that the request was called with
  • options - all options passed to the request
  • config - configuration of the matched API/alias path

Note: inside before[verb/all] hook this points to that provider's instance.

Take a look at the examples and the config/hooks.js file as it contains a couple of hooks bundled with Purest.

The only thing that you want modify in a before[verb/all] hook is the options argument. These hooks are executed right before the request is started, so that's the last chance to dynamically modify some of the passed options to that request in Purest. The request's defaults method (if present) is executed after the hook.

Note: Always write tests for your hooks, and execute those tests after each upgrade to a newer version of Purest!

Query Method Aliases

Purest comes with a bunch of pre-configured method aliases to use with its Query API:

{
  "verbs": {
    "get"      : ["select", "read"],
    "post"     : ["update", "send", "submit"],
    "put"      : ["create", "insert", "write"],
    ...
  },
  "options": {
    "qs"       : ["where"],
    "form"     : ["set"],
    "formData" : ["upload"],
    ...
    "options"  : []
  },
  "custom": {
    "auth"     : [],
    "request"  : []
  }
}

The actual methods are to the left, and their aliases are to the right.

Using the above configuration the following API calls are identical:

// var facebook = new Purest({provider:'facebook'})
facebook.query()
  .get('me')
  .request(function (err, res, body) {})
// same as
facebook.query()
  .select('me')
  .request(function (err, res, body) {})

However you may not be happy with the pre-defined aliases. Luckily you can define your own:

var facebook = new Purest({
  provider:'facebook',
  methods:{
    verbs:{get:['loot']},
    custom:{request:['submit']}
  }
})

Then the following code is valid:

facebook.query()
  .loot('me')
  .submit(function (err, res, body) {})

Note: Keep in mind that you should not use the actual method names as alias names.

Note: Your alias methods override any previously defined aliases with the same name.

Streaming

Purest always returns a request object, so streaming works as usual:

var Purest = require('purest')
var box = new Purest({provider:'box'})
  , dropbox = new Purest({provider:'dropbox'})

// move a file from Box to Dropbox
box.query()
  .get('files/21838973235/content')
  .auth('[ACCESS_TOKEN]')
  .request()
  .pipe(dropbox.query('files')
    .put('files_put/auto/cat.jpg')
    .auth('[ACCESS_TOKEN]')
    .request()
    .on('end', function () {}))

Using event-stream to process each line of data as it arrives:

var es = require('event-stream')
var Purest = require('purest')
var mailchimp = new Purest({provider:'mailchimp'})

// export Mailchimp contacts
mailchimp.query('export')
  .select('list')
  .where({id:'bd0b216f1c'})
  .auth('[API_KEY]')
  .request()
  .pipe(es.split())
  .pipe(es.map(function (contact, done) {
    // process each contact as it arrives
    done()
  }))

Promises

Purest can be configured to use Promises:

var facebook = new Purest({provider:'facebook', promise:true})

facebook.query()
  .get('me')
  .auth('[ACCESS_TOKEN]')
  .request()
  .spread(function (res, body) {
    console.log(res.statusCode)
    console.log(body)
  })
// OR
facebook
  .get('me', {auth:{bearer:'[ACCESS_TOKEN]'}})
  .spread(function (res, body) {})

You need the bluebird module installed first:

$ npm install bluebird

Generators

You can use Generators with the promisified Purest instance:

var co = require('co')
var facebook = new Purest({provider:'facebook', promise:true})

co(function* () {
  return yield facebook.query()
    .get('me')
    .auth('[ACCESS_TOKEN]')
    .request()
})
.then(function (results) {
  console.log(results[0].statusCode)
  console.log(results[1])
})
.catch(function (err) {
  console.log(err)
})

For this example to work you need the co module installed first: $ npm install co

Async Await

You can use async/await with the promisified Purest instance as well:

import 'babel/polyfill'
import Purest from 'purest'

var facebook = new Purest({provider:'facebook', promise:true})

async function task () {
  return await facebook.query()
    .get('me')
    .auth('[ACCESS_TOKEN]')
    .request()
}

task()
  .then((result) => {
    console.log(result[0].statusCode)
    console.log(result[1])
  })
  .catch((err) => {
    console.log(err)
  })

Take a look at the Promise Examples on how you can run this example.

OAuth

Most of the OAuth2 providers in the config/provider.json file have an alias called oauth.

Search for "alias": "oauth" in that file.

The {endpoint} token for each one of those oauth API/alias paths resembles the token word, part of that path:

"asana": {
  "https://app.asana.com": {
    "-/oauth_{endpoint}": {
      "__path": {
        "alias": "oauth"
      }
    }
  }
},
"box": {
  "https://api.box.com": {
    "oauth2/{endpoint}": {
      "__path": {
        "alias": "oauth"
      }
    }
  }
}

With the above configuration you can refresh the user's access token for Asana like this:

// var asana = new Purest({provider:'asana'})
asana.query('oauth')
  .post('token')
  .form({
    grant_type:'refresh_token',
    refresh_token:'[REFRESH_TOKEN]',
    client_id:'[APP_ID]',
    client_secret:'[APP_SECRET]'
  })
  .request(function (err, res, body) {})

Purest will make request to the https://app.asana.com/-/oauth_token endpoint of the Asana API.

In exactly the same way you can refresh the user's token for the Box API:

// var box = new Purest({provider:'box'})
box.query('oauth')
  .post('token')
  .form({
    grant_type:'refresh_token',
    refresh_token:'[REFRESH_TOKEN]',
    client_id:'[APP_ID]',
    client_secret:'[APP_SECRET]'
  })
  .request(function (err, res, body) {})

In this case Purest will make request to the https://api.box.com/oauth2/token endpoint of the Box API.

You are free to configure your API/alias paths as you want. Purest comes with pre-configured oauth path alias for most of the providers.

provider.query('oauth')
  .update('token')
  .set({
    grant_type:'client_credentials',
    client_id:'[APP_ID]',
    client_secret:'[APP_SECRET]'
  })
  .request(function (err, res, body) {})

Check your provider's documentation to see whether it supports that grant type.

provider.query('oauth')
  .update('token')
  .set({
    grant_type:'password',
    username:'[USERNAME]',
    password:'[PASSWORD]',
    client_id:'[APP_ID]',
    client_secret:'[APP_SECRET]'
  })
  .request(function (err, res, body) {})

Check your provider's documentation to see whether it supports that grant type.

provider.query('oauth')
  .update('token')
  .set({
    grant_type:'refresh_token',
    refresh_token:'[REFRESH_TOKEN]',
    client_id:'[APP_ID]',
    client_secret:'[APP_SECRET]'
  })
  .request(function (err, res, body) {})

Check your provider's documentation to see whether it supports that grant type.

Basic Auth

Some providers allow the application's credentials to be sent as Basic Authorization header as well:

// var acton = new Purest({provider:'acton'})
acton.query('oauth')
  .update('token')
  .set({grant_type:'client_credentials|password|refresh_token'})
  .auth({user:'[APP_ID]', pass:'[APP_SECRET]'})
  .request(function (err, res, body) {})

This grant type is implemented by Grant which is OAuth middleware for Express, Koa and Hapi. Alternatively you can use the OAuth Playground for testing.

// var yahoo = new Purest({provider:'yahoo'})
yahoo.query('oauth')
  .update('token')
  .oauth({
    consumer_key:'...',
    consumer_secret:'...',
    token:'...',
    token_secret:'...',
    session_handle:'...'
  })
  .request(function (err, res, body) {})

Search for "alias": "oauth" in config/providers.json to see how various oauth path aliases are configured for different providers.

Multipart Uploads

Multipart uploads works out of the box, just like in request:

multipart/form-data

// var facebook = new Purest({provider:'facebook'})
facebook.post('me/photos', {
  auth:{bearer:'[ACCESS_TOKEN]'},
  formData:{
    message:'My cat is awesome!',
    source:fs.createReadStream('cat.png')
  }
}, function (err, res, body) {})

Same as:

facebook.query()
  .update('me/photos')
  .upload({
    message:'My cat is awesome!',
    source:fs.createReadStream('cat.png')
  })
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

multipart/related

// var google = new Purest({provider:'google'})
google.post('files', {
  api:'upload-drive',
  auth:{bearer:'[ACCESS_TOKEN]'},
  qs:{uploadType:'multipart'},
  multipart: [
    {
      'Content-Type':'application/json',
      body:JSON.stringify({title:'cat.png'})
    },
    {
      'Content-Type':'image/png',
      body:fs.createReadStream('cat.png')
    }
  ]
}, function (err, res, body) {})

Same as:

google.query('upload-drive')
  .update('files')
  .where({uploadType:'multipart'})
  .upload([
    {
      'Content-Type':'application/json',
      body:JSON.stringify({title:'cat.png'})
    },
    {
      'Content-Type':'image/png',
      body:fs.createReadStream('cat.png')
    }
  ])
  .auth('[ACCESS_TOKEN]')
  .request(function (err, res, body) {})

Purest Specific Options

Additionally to the request's options, Purest adds a few more options on its own.

api

Specific API/alias path to use for providers with multiple paths configuration:

google.get('channels', {
  api:'youtube',
  auth:{bearer:'[ACCESS_TOKEN]'},
  qs:{forUsername:'RayWilliamJohnson'}
}, function (err, res, body) {})

version

Replaces the API [version] token embedded into the path configuration (if present):

"twitter": {
  "https://api.twitter.com": {
    "[version]/{endpoint}.[type]": {
      "__path": {
        "alias": "__default",
        "version": "1.1"
      }
    }
  }
}

Given the above configuration, all requests will default to version 1.1:

twitter.get('users/show', function (err, res, body) {})

Will result in request to the https://api.twitter.com/1.1/users/show.json endpoint using version 1.1 of the Twitter API.

You can change that using the version option:

twitter.get('users/show', {version:'1.0'}, function (err, res, body) {})

Will result in request to the https://api.twitter.com/1.0/users/show.json endpoint using version 1.0 of the Twitter API.

type

Again, using the above configuration for Twitter, we can change the value for the [type] token embedded into the path. If present [type] always defaults to json.

To override that pass the type option with the appropriate value:

twitter.get('users/show', {type:'xml'}, function (err, res, body) {})

Will result in request to the https://api.twitter.com/1.1/users/show.xml endpoint.

subdomain

Some domain configurations have a [subdomain] token embedded into them:

"mailchimp": {
  "https://[subdomain].api.mailchimp.com": {...}}

Mailchimp needs the user's data center name embedded into the domain:

// var mailchimp = new Purest({provider:'mailchimp'})
mailchimp.get('campaigns/list', {
  subdomain:'us2',
  qs:{apikey:'[API_KEY]'}
}, function (err, res, body) {})

Will result in request to the https://us2.api.mailchimp.com domain.

subpath

Some providers may have a [subpath] token embedded into them:

"basecamp": {
  "[subpath]/api/[version]/{endpoint}.[type]": {...}}

The BaseCamp API needs the user's ID embedded into the path:

// var basecamp = new Purest({provider:'basecamp'})
basecamp.get('people/me', {
  subpath:'123',
  auth:{bearer:'[ACCESS_TOKEN]'}
}, function (err, res, body) {})

Will result in request to the https://basecamp.com/123/api/v1/people/me.json endpoint.

oauth:secret

Shortcut for oauth:token_secret used to set the user's [ACCESS_SECRET]:

var twitter = new Purest({
  provider:'twitter',
  key:'[CONSUMER_KEY]', secret:'[CONSUMER_SECRET]'
})
twitter.get('users/show', {
  oauth:{token:'[ACCESS_TOKEN]', secret:'[ACCESS_SECRET]'},
  qs:{screen_name:'nodejs'}
}, function (err, res, body) {})

License

MIT

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.