
async function api ({state, commit, dispatch}, [resource, init = {}, cb]) {
  try {
    commit("queueRequest");
    if (init && init.hasOwnProperty("body")) {
      if (!init.headers) {
        // As a convenience, we implicitly add the default content type
        init.headers = {
          "Content-Type": "application/json"
        }
      }
      if (typeof init.body != "string") {
        init.body = JSON.stringify(init.body);
      }
    }
    const url = /^https?:\/\//i.test(resource) ? resource : (state.apiUrl + resource);
    const res = await fetch(url, init);
    if (typeof cb === 'function') {
      await cb(null, res);
    }
    if (res.ok) {

      await dispatch('setCredentials');

      try {
        return init.text ? (await res.text()) : (await res.json());
      } catch (err) {
        if (err instanceof SyntaxError) {
          if (Number(res.headers.get("Content-Length")) === 0) {
            // res.json() cannot parse an empty response and we
            // have run into this case. We just return undefined.
            return;
          }
        }
        throw err;
      }
    } else {
      let message = res.statusText;
      if (res.headers.get("Content-Type").match(/^application\/json/i)) {
        const body = await res.json();
        if (body.message) {
          message = body.message;
        }
      }
      await dispatch('showSnack', [message, "warning"]);
    }
  } catch (err) {
    if (err && err.name == "AbortError") return;
    await dispatch('showSnack', [err, "error"]);
    if (typeof cb === 'function') {
      cb(err);
    }
  } finally {
    commit("dequeueRequest");
  }
}

export default { api };
