ordercloud-javascript-sdk
OrderCloud
The OrderCloud SDK for Javascript is a modern client library for building solutions targeting the Ordercloud eCommerce API. The SDK aims to greatly improve developer productivity and reduce errors.
- ✨ Features
- Requirements
- ⚙️ Installation
- ➕ Adding it to your project
- 🔐 Authentication
- 🔍 Filtering
- 👬 Impersonation
- Configuration
- Handling Errors 🐛
- Interceptors
- Cancelling Requests
- Async/Await
- Typescript Support
- 📄 License
- 🤝 Contributing
- 🆘 Getting Help
✨ Features
- Works both on the browser and node.js
- ESM module available for bundlers that support it. This enables tree shaking – use only what you import.
- Built-in Typescript support, no additional types package necessary
- Full feature parity with API
- Auto-generated API reference
Coming from an older version? Check out the migration guide so you can upgrade to the latest and greatest.
Requirements
Axios is a peer dependency of the OrderCloudSDK.
Note: Peer dependencies are not installed automatically. They must be installed separately.
Why isn’t axios a dependency of OrderCloud SDK? Since axios is a fairly popular http library and may already exist as a dependency in your project it is considered best practice to have it defined as a peer dependency. This way, there isn’t a potential for two versions of axios to be installed which could result in weird bugs, not to mention a bloated javascript bundle.
⚙️ Installation
with npm:
npm install ordercloud-javascript-sdk --save
or
with yarn:
yarn add ordercloud-javascript-sdk
➕ Adding it to your project
Using named imports
This is the preferred method of importing the sdk for browser projects as it allows modern bundlers like webpack to tree shake the parts of the SDK that you aren’t using, making your project more lean.
import { Products } from 'ordercloud-javascript-sdk';
Using wildcard import
import * as OrderCloudSDK from 'ordercloud-javascript-sdk';
Using require
const OrderCloudSDK = require('ordercloud-javascript-sdk');
🔐 Authentication
We’ll need to get a token before we can make any API calls. The SDK offers five different ways of getting a token as part of the Auth class.
We’ll use the login method for this example.
import { Auth, Tokens } from 'ordercloud-javascript-sdk'; const username = 'YOUR_USERNAME'; //username of the user logging in const password = 'YOUR_PASSWORD'; //password of the user logging in const clientID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'; //clientID of the application the user is logging in to ([sign up for free](https://portal.ordercloud.io/register) const scope = ['FullAccess']; //string array of [roles](https://ordercloud.io/knowledge-base/security-profiles) the application has access to Auth.Login(username, password, clientID, scope) .then(response => { //store token, now any subsequent calls will automatically set this token in the headers for you const token = response.access_token; Tokens.SetAccessToken(token) }) .catch(err => console.log(err));
🔍 Filtering
All of the filtering options you love from the API are available through the SDK as well. Simply build an object that matches the model of the item you’re filtering on where the value
is the value you’d like to filter on.
Let’s run through a couple scenarios and what the call will look like with the SDK:
My products where xp.Featured
is true
Me.ListProducts({ filters: { 'xp.Featured': true } }) .then(productList => console.log(productList));
My orders submitted after April 20th, 2018
Me.ListOrders({ filters: { DateSubmitted: '>2020-04-20' } }) .then(orderList => console.log(orderList))
Users with the last name starting with Smith:
Users.List('my-mock-buyerid', { filters: { LastName: 'Smith*' } }) .then(userList => console.log(userList));
Users with the last name starting with Smith or users with the last name ending with Jones
Users.List('my-mock-buyerid', { filters: { LastName: 'Smith*|*Jones' } }) .then(userList => console.log(userList));
Products where xp.Color is not red and not blue
Products.List({ filters: { 'xp.Color': ['!red', '!blue'] } }) .then(productList => console.log(productList));
And of course you can mix and match filters to your heart’s content.
👬 Impersonation
Impersonation allows a seller user to make an API call on behalf of another user. The SDK enables this in two ways, each tackling different use cases.
The first method we’ll talk about is best suited when you need to toggle between just two users during a session. You’ll simply get an impersonation token, set it and then use the As()
method available on every service to flag the SDK that you want to use the the stored token for that call.
import { Tokens, Me } from 'ordercloud-javascript-sdk'; // set regular token const myToken = 'YOUR_TOKEN'; Tokens.SetAccessToken(myToken); // set impersonation token const myImpersonationToken = 'YOUR_IMPERSONATED_TOKEN' Tokens.SetImpersonationToken(myImpersonationToken); // Get products for regular user Me.ListProducts() .then(productList => console.log(productList)) // Get products for the impersonated user Me.As().ListProducts() .then(impersonatedProductList => console.log(impersonatedProductList))
As you can see this method makes it very easy to toggle between impersonated calls and non-impersonated calls. But what if you have more than two tokens to toggle between? To address that scenario we recommend using the optional requestOptions.accessToken
parameter. requestOptions
is available as the last parameter on all sdk methods.
import { Me } from 'ordercloud-javascript-sdk'; var token1 = 'USER1_TOKEN'; var token2 = 'USER2_TOKEN'; var token3 = 'USER3_TOKEN'; // Get products for user 1 Me.ListProducts(null, { accessToken: token1 }) .then(user1ProductList => console.log(user1ProductList)) // Get products for user 2 Me.ListProducts(null, { accessToken: token2 }) .then(user2ProductList => console.log(user2ProductList)) // Get products for user 3 Me.ListProducts(null, { accessToken: token3 }) .then(user3ProductList => console.log(user3ProductList))
Configuration
The Configuration
service can be used to set sdk level options.
Simply set the options you need to override and the SDK will merge it with the default options object.
import { Configuration } from 'ordercloud-javascript-sdk'; Configuration.Set({ baseApiUrl: 'https://sandboxapi.ordercloud.io', timeoutInMilliseconds: 20 * 1000 })
Similarly, you can see what the current options are by using the getter.
import { Configuration } from 'ordercloud-javascript-sdk'; const configuration = Configuration.Get(); console.log(configuration); // the current sdk configuration
The SDK uses a custom error (OrderCloudError
) to provide rich and useful information in the case of an error.
Products.Get('my-product') .catch(error => { if(error.isOrderCloudError) { // the request was made and the API responded with a status code // that falls outside of the range of 2xx, the error will be of type OrderCloudError // https://ordercloud-api.github.io/ordercloud-javascript-sdk/classes/orderclouderror console.log(error.message); console.log(JSON.stringify(error.errors, null, 4)); } else if (error.request) { // the request was made but no response received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js console.log(error.request); } else { // Something happened in setting up the request that triggered an Error console.log('Error', error.message); } })
Interceptors
You can use axios interceptors to intercept a request before it goes out to the API or to intercept a response before it gets handled by the SDK. This enables you to log, rewrite, or even retry calls.
The SDK does not use a custom axios instance, so you can set up your interceptors right off of axios.
// Add a request interceptor axios.interceptors.request.use(function (config) { // Do something before request is sent return config; }, function (error) { // Do something with request error return Promise.reject(error); }); // Add a response interceptor axios.interceptors.response.use(function (response) { // Any status code that lie within the range of 2xx cause this function to trigger // Do something with response data return response; }, function (error) { // Any status codes that falls outside the range of 2xx cause this function to trigger // Do something with response error return Promise.reject(error); });
Cancelling Requests
In addition to requestOptions.accessToken
the sdk provides requestOptions.cancelToken
which enables axios request cancellation. This option is useful for cleaning up outstanding requests when changes in your user experience no longer require the data requested. For instance, you could use the cancel token to clean up outstanding requests when your react component unmounts.
import axios from 'axios'; import { Products } from 'ordercloud-javascript-sdk'; const signal = axios.CancelToken.source(); Products.List({search: 'Tennis balls'}, {cancelToken: signal.token}) .catch(ex => { if (axios.isCancel(ex)) { console.log(ex) // 'This request was cancelled!' } else { console.log(ex) // Normal ordercloud exception } }) // Oops! I don't want to resolve this request anymore signal.cancel('This request was cancelled!')
Async/Await
Async/Await is a special syntax to work with promises in a more comfortable fashion. Because the SDK is built with promises the syntax works right out of the box – simply add the async
keyword to your outer function method.
// with normal promises (() => { Auth.Login('myusername', 'mypassword', 'myclientID', ['FullAccess']) .then(authResponse => { Tokens.SetAccessToken(authResponse.access_token) Me.ListOrders().then(orderList => { const firstOrder = orderList.Items[0] console.log(firstOrder.Total) }) }) .catch(err => { console.log(err) }) })()
// with async/await (async () => { try { const authResponse = await Auth.Login('myusername', 'mypassword', 'myclientID', ['FullAccess']) Tokens.SetAccessToken(authResponse.access_token) const myOrders = await Me.ListOrders() const firstOrder = myOrders.Items[0] } catch (err) { console.error(err) } })()
NOTE: async/await is part of ECMAScript 2017 and is not supported in Internet Explorer and older browsers without first transpiling to ES5 so use with caution.
Typescript Support
While Typescript is not required to use this project (we compile it down to ES5 javascript for you), it does mean there are some added benefits for our Typescript users. You will need a minimum of typescript version 3.5 for all features to work correctly.
Understanding OrderCloud’s models
By default, properties of ordercloud models are required if their Create or Save operation requires them. For example the LineItem
model has the properties ProductID
and Quantity
required. This is important to know if you need to define an object by type before using it.
import { LineItems, LineItem } from 'ordercloud-javascript-sdk'; const lineItem: LineItem = { ProductID: 'my-awesome-product', // if this field is missing you get a type error! Quantity: 2 // if this field is missing you get a type error! } LineItems.Create('Outgoing', 'my-order-id', lineItem)
This works as expected and ensures a create or save always has the correct required parameters. However, if for example you need to perform a Patch operation (partial update), then you want all of the fields to be optional. To accomplish this you should use Typescript’s built-in utility type Partial<T>
import { LineItems, LineItem } from 'ordercloud-javascript-sdk'; const lineItem:...