Hi all,

So far I am keeping myself on track to work a bit every weekend on my side projects.

That being said, I am a big fan on JSON:API and in my search for streamlining the consumption on the front-end I’ve finally settled on a nifty JSON:API client called Devour. It has the right amount of magic to make it worthwile and not be over the top ‘magical’.

For that, I’ve made a small nuxt.js plugin that allows me to use it regardless if it’s in a component or in the vuex store.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import JsonApi from "devour-client";
import * as apis from "~/api/index.js";

export default (ctx, inject) => {
  // eslint-disable-next-line no-undef
  const jsonApi = new JsonApi({ apiUrl: CONFIG.backend.url });
  const apiMap = {};

  for (const [key, value] of Object.entries(apis)) {
    jsonApi.define(
      apis[key].structure().modelName,
      apis[key].structure().fields
    );
  }

  for (const [key, value] of Object.entries(apis)) {
    // eslint-disable-next-line no-undef
    apiMap[key] = new apis[key](jsonApi, CONFIG);
  }

  apiMap.jsonApi = jsonApi;

  // Inject into the nuxt/vue context
  ctx.$api = apiMap;
  inject("api", apiMap);
};

The CONFIG constant is generated by the following library config and injected into the app for easy access.

To use the plugin, index.js is a generic export for the various API models that we’re going to use.

1
export { default as InventoryItem } from "./InventoryItem";

The model is nothing more than a simple object that returns the required configuration for the api and exposes it after trough its own methods.

I’d rather not tightly couple the app to Devour, so keeping them into our own classes should make it easier to swap it out going forward, and/or just use axios directly if needed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
export default class InventoryItem {
  constructor(api, config) {
    this.api = api;
    this.config = config;
  }

  static structure() {
    return {
      modelName: "inventory-item",
      fields: {
        name: ""
      }
    };
  }

  getInventoryItems() {
    return this.api.findAll(InventoryItem.structure().modelName);
  }
}

I am curious on knowing how you guys are separating your API calls in your own SPA apps