Skip to content

Instantly share code, notes, and snippets.

@Sparragus
Created May 24, 2019 14:21
Show Gist options
  • Save Sparragus/79b0cd92f0e739f3e027f072301fe9ee to your computer and use it in GitHub Desktop.
Save Sparragus/79b0cd92f0e739f3e027f072301fe9ee to your computer and use it in GitHub Desktop.
An example of how I build my own API library for each project
import { readAuthCookie } from '../helpers/cookie';
import * as errorTracker from '../helpers/errorTracker';
/*
Helpers
*/
const BASE_PATH = '/api/v1';
class APIError extends Error {
constructor(res, data) {
super(
data.errors
? data.errors[0]
: data.error || data.message || res.statusText || res.status
);
this.name = 'APIError';
this.type = data.type;
this.status = res.status;
this.statusText = res.statusText;
}
}
function buildPath(path) {
const normalizedPath = path[0] === '/' ? path : `/${path}`;
return BASE_PATH + normalizedPath;
}
function makeRequest(path, options) {
const { method = 'GET', body, headers = {} } = options;
const normalizedBody = typeof body === 'object' ? JSON.stringify(body) : body;
const authCookie = readAuthCookie();
if (authCookie) {
headers['Authorization'] = `Bearer: ${authCookie}`;
}
headers['Content-Type'] = 'application/json';
headers['Accept'] = 'application/json';
return new Request(buildPath(path), {
method,
body: normalizedBody,
headers,
});
}
async function callApi(path, options) {
const req = makeRequest(path, options);
const res = await window.fetch(req);
if (!res.ok) {
let data = {};
try {
data = await res.json();
} catch (error) {}
throw new APIError(res, data);
}
if (res.status == 204) {
return;
}
try {
return await res.json();
} catch (error) {
// The server's response was not application/JSON
errorTracker.log(
new Error(
`Expected a JSON response for ${req.method} ${
req.url
}. Got something else.`
)
);
return {};
}
}
/*
API Calls
*/
export const Conversations = {
async list() {
const path = '/conversations';
const data = await callApi(path, {
method: 'GET',
});
return data.conversations;
},
async get(id) {
const path = `/conversations/${id}`;
const data = await callApi(path, {
method: 'GET',
});
return data.conversation;
},
async create(payload = {}) {
const { recipientId, subject, message } = payload;
const path = '/conversations';
const data = await callApi(path, {
method: 'POST',
body: {
recipient_id: recipient_id,
subject,
body: message,
},
});
return data.conversation;
},
};
export const Messages = {
async list(conversationId) {
const path = `/conversations/${conversationId}/messages`;
const data = await callApi(path, {
method: 'GET',
});
return data.messages;
},
async send(conversationId, payload = {}) {
const { message } = payload;
const path = `/conversations/${conversationId}/messages`;
const data = await callApi(path, {
method: 'POST',
body: { body: message },
});
return data.message;
},
};
@Sparragus
Copy link
Author

Here's an example of how to use this:

import React from 'react';
import * as api from '../../lib/api';

export default function ConversationsTable (props) {
  const [ data, setData ] = React.useState();
  const [ loading, setLoading ] = React.useState(true);
  const [ error, setError ] = React.useState(null);

  React.useEffect(() => {
    async function fetchConversations() {
      setLoading(true);
      setError(null);

      try {
        const data = await api.Conversations.list();
        setData(data);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchConversations();
  }, []);

  if (loading) {
    return 'Loading...';
  }

  if (error) {
    return error.message;
  }

  return (
    <ul>
      data.map(conversation => (
        <li key={conversation.id}>
          {conversation.subject}
        </li>
      ))
    </ul>
  );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment