npm package: @icentris/onyx-services
Description: Onyx Services
Latest version: 1.0.16

# onyx-services

The place where your API implementations go.  Currently only `VibeApi` is available but will likely include service provider classes for additional vendors in the future (ie: content, localization, etc.)

Typically used for accessing external resources from within your `getStore` function -- `onyx-app`'s `<StoreWrapper />`  provides a `vibeApi` instance to it's `getStore` call.

## Conventions for Services

- **Always** return a `Promise` from your service calls.
  - This allows for chaining the success / failure result from the calling locationthe calling location
- **Avoid** `async` / `await` in favor of `Promise`
- **Camelize** returned data structure.
  - Use `onyx-common/camelize`, just pass the obj in it takes care of the rest:

```javascript
import camelize from 'onyx-common/camelize'

const obj = {
  first_name: 'Bob',
  last_name: 'Johnson'
}

const camelizedObj = camelize(obj)

/*
camelizedObj  = {
    firstName: 'Bob',
    lastName: 'Johnson'
}
*/
```

- **Always** use traditional `function ()` syntax for class methods
  - If arrow methods `() => {}` are used, the `this` context is lost from the compiled class.

## `fetchWrap` helper

`fetchWrap` wraps the default `fetch` function to make it a bit more friendly to use.  It accepts the following options:

- **url**: The URL to use for this request
- **method**: `POST`, `DELETE` or `GET`.  `GET` is default
- **data**: an array of data to send with request
- **urlMerge**: if you provide placeholders in the `url` in the form of `http://google.com/{foo}/{bar}` send in an array with `{ 'foo': '1', 'bar': '2' }` and it becomes `http://google.com/1/2`
- **requestType**: `json` or `form` to change request headers. Has no impact on `GET` requests
- **fetchOptions**: direct fetch api options to pass through and override any convenience additions

It also wraps the return to make it easier to work with and ensure a promise is always returned.

[Learn more](../onyx-common/src/fetchWrap/fetchWrap.js)

## Structure of a Service Class

To make services more manageable, they should be broken out into sub files for each area of responsibility (roughly mapped often to `onyx-scenes-*` packages, but not neccessarily).  responsibilities and then rolled up into a single namespace.

Here's an example of how the `VibeApi` class is composed:

### Base object with `constructor` and other shared functionality

`VibeApi/VibeApiBase.js`

```javascript
const VibeApiBase = function () {}

VibeApiBase.prototype.constructor = function ({ baseUrl }) {
  this.baseUrl = baseUrl
}

VibeApiBase.prototype.getUrl = function (path) {
  return this.baseUrl + path
}

export default VibeApiBase
```

### Add one or more `prototype` decorators

`VibeAPi/VibeApiAuth.js`

```javascript
import formurlencoded from 'onyx-common/form-urlencoded'
import urlencode from 'onyx-common/urlencode'
import fetchWrap from 'onyx-common/fetchWrap'
import camelize from 'onyx-common/camelize'

const VibeApiAuth = ({ prototype }) => {
  prototype.login = function ({ username, password }) {
    // ...rest of function

    // example of how to use fetchWrap helper
    return fetchWrap(payload)
      .then(res => Promise.resolve(normalize(res)))
      .catch(error => Promise.reject(Error('loginError', error)))
  }

  prototype.logout = function ({ authenticationToken }) {
    // ...rest of function

    // example of how to use fetchWrap helper
    return fetchWrap(payload)
      .then(() => Promise.resolve())
      .catch(() => Promise.reject(Error('logoutError')))
  }
}

export default VibeApiAuth
```

### Combine Base & decorator(s)

`VibeApi/VibeApi.js`

```javascript
import VibeApi from './VibeApiBase'
import VibeApiAuth from './VibeApiAuth'
// add more decorators in the future
// import VibeApiResourceLibrary from './VibeApiResourceLibrary'

// decorate the prototype
VibeApiAuth(VibeApi)

// add more decorators in the future
// VibeApiResourceLibrary(VibeApi)

export default VibeApi
```

The final class is now usable like so:

```javascript
import VibeApiFactory from 'onyx-services/VibeApi'

const VibeApi = new VibeApiFactory({
  baseUrl: '/your/base/url'
})
```