3 Steps to Make Any Node.JS API Library Better

Jack Yeh
Jack Yeh
Oct 17 · 4 min read

What I wish every Library author would do in the world of API Libraries.

Image for post
Image for post
Photo by Brad Barmore on Unsplash

Background

Below are three things that would drastically improve the usability of an API Library for end users. Library Authors, if you care about gaining more users, please make them happen!

1. Include Type Definition

logger.info(`Result: ${JSON.stringify(response.data, null, 4)}`);

calls to figure out what fields are available. When Request/Response types are specified, it can save end users a lot of time! Another place where this is important is during the constructor calls:

const ImaginaryClient = require('imaginary-client');const client = new ImaginaryClient({
domain: config.domain,
username: config.username,
token: config.token
});

Rather than requiring the user to go back to the Github Readme page once in a while to recall what input signature ImaginaryClient has, or digging into the node_modules folder to figure out how to call this function, if a type definition is included, it would save user a lot of time and we really would thank you for this.

Example: https://github.com/getsentry/sentry-javascript/blob/master/packages/types/src/options.ts

/** Base configuration options for every SDK. */
export interface Options {
/**
* Enable debug functionality in the SDK itself
*/
debug?: boolean;

/**
* Specifies whether this SDK should activate and send events to Sentry.
* Disabling the SDK reduces all overhead from instrumentation, collecting
* breadcrumbs and capturing events. Defaults to true.
*/
enabled?: boolean;

/**
* The Dsn used to connect to Sentry and identify the project. If omitted, the
* SDK will not send any data to Sentry.
*/
dsn?: string;
...
}

2. Provide the ability to Create AXIOS Requests rather than making the call

But, what if the endpoint changes? If a path no longer expects an Id, but now needs an UUID, users can no longer use the same library to make the calls anymore. We have a couple of options:

a. Write our own request calls — Since the Library is taking an input and translating it into an AXIOS or other request/fetch calls, we can use it as a reference and make our own request calls with correct details.
b. Fork the library and fix it in a pull-request — This requires the user to study the library a little bit and make the appropriate fixes and get it merged into upstream.

Both of which are not quick by any means.

Which is why Library authors should add the option of returning the request payload, and let end user do the actual calls themselves.

Example: https://github.com/androozka/zendesk-api-js

try {
const { tags } = zdApi.support.init(options);
const data = { tags: ['tag_1', 'tag_2', ... ] }

const req = tags.add({ type: 'tickets', id: 123, data });

const res = await axios(req);
} catch (error) {
// ...
}

Rather than making the actual calls for us, the library above returns “req”, which is a plain JSON object that we can send to AXIOS to make the call ourselves.

If there are any incorrectly formatted urls, user can immediately get around this issue by monkey patching the req object.

We get to finish our tasks without needing to craft our own requests, or dig deeper into the library to fix the problem. Adopting this pattern saves users a lot of time and headaches!

3. Avoid require() calls in Library usage

To make sure not all of the files are loaded, many Library chooses to dynamically load different sets of files depending on the inputs.

This is a nice gesture, but it makes testing the code more difficult. Jest for example would complain about require() code being made while the test is being run.

ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.

If the sets of files are truly large, I would recommend the author breaking them into separate packages.

For less than 100 URI endpoints, please do include all of them statically. This makes type definition (from step 1) easier to do, and save us the trouble with testing frameworks!

Conclusion

  1. Include Type Definition
  2. Allow Request Construction
  3. Avoid Dynamic require() calls anywhere
Image for post
Image for post
Photo by Yiqun Tang on Unsplash

TeamZeroLabs

Sharing concepts, ideas, and code for modern development

Jack Yeh

Written by

Jack Yeh

I monitor your full stack deployment in production, so you can sleep at night. Docker | Kubernetes | AWS | Prometheus | Grafana

TeamZeroLabs

Sharing concepts, ideas, and code for modern development

Jack Yeh

Written by

Jack Yeh

I monitor your full stack deployment in production, so you can sleep at night. Docker | Kubernetes | AWS | Prometheus | Grafana

TeamZeroLabs

Sharing concepts, ideas, and code for modern development

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store