Skip to content
This repository has been archived by the owner on Jan 12, 2021. It is now read-only.

Latest commit

 

History

History
232 lines (160 loc) · 6.92 KB

UPGRADE.md

File metadata and controls

232 lines (160 loc) · 6.92 KB

Upgrading to Foxy SDK

Import

Before

Node API used to export a FoxyApi class:

// CJS (Node 10-12)
const { FoxyApi } = require("@foxy.io/node-api");

// ESM (TypeScript, Node 13+)
import { FoxyApi } from "@foxy.io/node-api";

const api = new FoxyApi({
  clientId: "client_MY-CLIENT-ID",
  clientSecret: "long-alphanumeric-client-secret",
  refreshToken: "long-alphanumeric-refresh-token",
});

After

Foxy SDK has a namespace export. You can find a hAPI client under Integration:

// CJS (Node 10-12)
const FoxySDK = require("@foxy.io/sdk");

// ESM (TypeScript, Node 13+)
import * as FoxySDK from "@foxy.io/sdk";

const api = new FoxySDK.Integration.API({
  clientId: "client_MY-CLIENT-ID",
  clientSecret: "long-alphanumeric-client-secret",
  refreshToken: "long-alphanumeric-refresh-token",
});

Env vars

Before

If you did't provide the full configuration, our hAPI client would look for the missing values in the following env vars:

FOXY_API_CLIENT_ID     # config.clientId
FOXY_API_CLIENT_SECRET # config.clientSecret
FOXY_API_REFRESH_TOKEN # config.refreshToken

After

Foxy SDK doesn't support this out of the box, but you can always use process.env to achieve the same effect (and you can use your own env vars as well):

const api = new FoxySDK.Integration.API({
  clientId: process.env.FOXY_API_CLIENT_ID,
  clientSecret: process.env.FOXY_API_CLIENT_SECRET,
  refreshToken: process.env.FOXY_API_REFRESH_TOKEN,
});

Cache

Before

In Node API package you could set config.cache to persist credentials between service invocations if it provided better performance for your use case:

const api = new FoxyApi({
  cache: new FoxyApi.cache.DiskCache("/tmp/.api_cache"),
});

After

You can pass any datastore implementing Web Storage API to config.storage to do the same in our SDK.

import { LocalStorage } from "node-localstorage";

const api = new FoxySDK.Integration.API({
  storage: new LocalStorage("/tmp/.sdk_storage"),
});

Please note that we've removed our own DiskCache, MemoryCache and MixedCache in favor of 3rd-party packages such as node-localstorage or fake-storage.

You SHOULD NOT use cache files generated by @foxy.io/node-api with @foxy.io/sdk as there may be differences in data schemas.

Logging

Before

Node API used Winston for logging, so you could specify options like these to control the output:

const api = new FoxyApi({ logLevel: "debug" });
const api = new FoxyApi({ silent: true });

After

SDK uses Consola and accepts a numeric config.level property instead (see available values):

const api = new FoxySDK.Integration.API({ level: 4 });
const api = new FoxySDK.Integration.API({ level: -Infinity });

Fetching data

Before

Node API package had a single .fetch() method on every resource or collection reference that would return parsed JSON or throw an error if request failed:

const store = await api.follow("fx:store").fetch();

You could also follow and fetch linked resources by calling api.from():

const store = await api.from(transaction).follow("fx:store").fetch();

And you could always use .fetchRaw() for low-level interactions:

const store = await api.fetchRaw({
  url: new URL("/stores/8", FoxyApi.endpoint),
});

After

Foxy SDK, on the other hand, exposes a number of methods for making requests: .get(), .put(), .post(), .patch() and .delete(). Each one of those methods returns a Response with status and body accessors:

const response = await api.follow("fx:store").get();
const store = await response.json();

Note: .get() accepts the same parameters as .fetch() of the Node API, except for query – SDK has filters property for that:

api
  .follow("fx:store")
  .follow("fx:transactions")
  .get({ filters: ["customer_id=123"] });

To access linked resources, simply call one of the methods listed above on the required link the _links section of the response body obtained with response.json():

const response = await transaction._links["fx:store"].get();
const store = await response.json();

For low-level interactions you can use .fetch() on the api instance – it implements exactly the same interface as the fetch() method of Fetch API:

const response = await api.fetch(new URL("/stores/8", api.base).toString());
const store = await response.json();

Smart Resolution

Before

With Node API you could .follow() a numeric resource ID like this:

const transaction = await api
  .follow("fx:store")
  .follow("fx:transactions")
  .follow(123)
  .fetch({ method: "GET" });

API client would use smart resolution to match the curie and the numeric ID to a hardcoded hAPI resource URL, and then make a single request to /transactions/123.

After

Even though we tried our best to make smart resolution as compatible as possible with our Hypermedia API, we still couldn't find a good way to make it fail-safe. To ensure the reliability of our SDK, we've decided to remove smart resolution from our API clients.

If you're fetching collections, you don't need to change anything. If you're fetching single resources by ID, you can use filters instead:

const transaction = await api
  .follow("fx:store")
  .follow("fx:transactions")
  .get({ filters: ["id=123"] })
  .then((response) => response.json())
  .then((json) => json._embedded["fx:transactions"][0]);

And of course you can always fetch a URL if you know it:

const transaction = await api.fetch("/transactions/123").then((response) => response.json());

We use cache to reduce the number of API requests, so if you're making a request to the same endpoint over and over again, our SDK will most likely perform a full API tree traversal only once. An in-memory cache is used by default, but you can also persist it to disk by passing any datastore implementing Web Storage API to config.cache:

import { LocalStorage } from "node-localstorage";

const api = new FoxySDK.Integration.API({
  cache: new LocalStorage("/tmp/.sdk_cache"),
});

HMAC, Signing, Utilities

If you're using utilities such as FoxySigner, you'll find them unchanged in FoxySDK.Integration namespace:

Before

import { FoxySigner } from "@foxy.io/node-api/dist/signer";
const hmacSign = new FoxySigner();

After

import * as FoxySDK from "@foxy.io/sdk";
const hmacSign = new FoxySDK.Integration.Signer();