Typesafe API Call Utility
typesafe-api-call is a minimalistic JavaScript library designed to streamline API interactions by enforcing typesafety and a functional programming paradigm. It abstracts away traditional exception handling, instead ensuring that every API call resolves to an explicit `APISuccess` or `APIFailure` result, compelling developers to handle both successful and unsuccessful outcomes distinctly. The library is currently on version 5.1.2 and appears to have an active release cadence, with recent patches and new features like `callWithRetries` introduced in minor versions. A key differentiator is its emphasis on functional results over exceptions, promoting predictable state management. It also integrates seamlessly with complementary tools like `type-decoder` and `type-crafter` to facilitate YAML-driven type and decoder generation, further enhancing end-to-end typesafety for API responses.
Common errors
-
TypeError: APICaller.call is not a function
cause Incorrect module import, especially in CommonJS environments prior to v5.1.1, or attempting to access `call` on an undefined `APICaller`.fixEnsure you are using `import { APICaller } from 'typesafe-api-call';` (ESM) and have updated to `typesafe-api-call@^5.1.1` or later. Verify that `APICaller` is correctly imported and not `undefined`. -
ReferenceError: APISuccess is not defined
cause The `APISuccess` class was not correctly imported from the `typesafe-api-call` package.fixAdd `import { APISuccess } from 'typesafe-api-call';` to the top of your file. Remember it's a named export. -
Property 'data' does not exist on type 'unknown'.
cause This error occurs when you attempt to access properties like `data` or `error` on the `APISuccess` or `APIFailure` instances without properly defining the type parameters (`T` and `U`) in `APIResponse<T, U>`, or without implementing the decoding functions correctly.fixEnsure your `APIResponse` is correctly typed (e.g., `APIResponse<MyDataType, ErrorType>`) and that the success/error decoding functions passed to `APICaller.call` return the expected types. The example's `(successResponse: unknown) => successResponse as Post[]` is a minimal cast; for production, implement actual type guards or decoders.
Warnings
- breaking Prior to version 5.1.1, users utilizing CommonJS environments or specific bundler configurations might have encountered issues resolving the main package entrypoint.
- gotcha This library replaces traditional `try/catch` blocks for network and API errors with a functional result pattern (`APISuccess` | `APIFailure`). Direct exception handling for API calls will bypass this pattern.
- gotcha The `call` method requires two decoding functions: one for a successful API response and one for an erroneous API response. If these are not provided or implemented correctly, the `data` or `error` properties within `APISuccess` or `APIFailure` will remain `unknown`.
- gotcha The `url` property in `APIRequest` strictly expects a `URL` object, not a string. Passing a string will result in a runtime TypeError.
Install
-
npm install typesafe-api-call -
yarn add typesafe-api-call -
pnpm add typesafe-api-call
Imports
- APICaller
const APICaller = require('typesafe-api-call').APICaller;import { APICaller } from 'typesafe-api-call'; - APIResponse
import APIResponse from 'typesafe-api-call';
import { APIResponse } from 'typesafe-api-call'; - APISuccess
import { APISuccess } from 'typesafe-api-call/lib';import { APISuccess } from 'typesafe-api-call'; - APIRequest (type)
import type { APIRequest } from 'typesafe-api-call';
Quickstart
import { APICaller, APIResponse, type APIRequest, APISuccess } from 'typesafe-api-call';
interface Post {
userId: number;
id: number;
title: string;
body: string;
}
const serverEndpoint = 'https://jsonplaceholder.typicode.com';
async function getAllPosts(): Promise<APIResponse<Post[], unknown>> {
const apiRequest: APIRequest = {
url: new URL(`${serverEndpoint}/posts`),
method: 'GET'
};
// Using an anonymous function for decoding. In a real app, you'd use a dedicated decoder.
const apiResponse = await APICaller.call(
apiRequest,
(successResponse: unknown) => successResponse as Post[], // Simulate decoding
(errorResponse: unknown) => errorResponse // Error handling can also include decoding
);
return apiResponse;
}
async function runExample() {
console.log('Fetching all posts...');
const getAllPostResult = await getAllPosts();
if (getAllPostResult instanceof APISuccess) {
console.log('Successfully fetched posts:', getAllPostResult.data.slice(0, 2));
} else {
console.log('Failed to fetch posts:', getAllPostResult.error);
}
}
runExample();