Skip to main content

Introduction

Zimic is a collection of TypeScript-first HTTP integration libraries. It provides type-safe utilities to make, receive, and mock HTTP requests and responses. Zimic is designed to be lightweight and easy to use, with type inference and validation built-in.

Motivation

Integrating with real-world HTTP APIs is very common in web development, yet keeping clients and servers in sync is still a challenging task. Developers often have to rely on documentation, SDKs, or even source code review and experimentation to declare correct types for the interactions with the API. In the end, we might end up with code like this:

interface GitHubRepository {
id: number;
name: string;
owner: { login: string };
}

// Let's fetch a repository from the GitHub API
const url = 'https://api.github.com/repos/zimicjs/zimic';
const response = await fetch(url);
const repository = (await response.json()) as GitHubRepository;

console.log(repository);
// { id: 721827056, name: 'zimic', owner: { ... }, ... }

One of the main issues with this approach is that the implementation is assuming many things about the structure of the API, with little validation to check if these assumptions are correct:

  • Manual types: the GitHubRepository interface is defined manually and can differ from the actual response, either by mistakes or by changes in the API.
  • Insufficient validation: paths and parameters are not validated, so typos or changes in the API will cause runtime issues without any type errors during development.
  • Response casting: the response body is manually cast to GitHubRepository, which can be repetitive, error-prone, and difficult to maintain.

In fact, did you spot the bug in this example? Because of the casting with as, the code assumes that the response data will always be of type GitHubRepository, regardless of the status code. However, that is not the case. If the request fails, the data can contain an error with a totally different structure!

const url = 'https://api.github.com/repos/zimicjs/i-dont-exist';
const response = await fetch(url);
const repository = (await response.json()) as GitHubRepository;

console.log(response.status); // 404
console.log(repository);
// { "message": "Not Found", "status": "404" } -- Oops

These issues are increased the more complex the API is and the more frequently it changes. As more endpoints are integrated, the API structure can become diluted in hundreds of manual types, casts, and unchecked paths and property names scattered across the codebase. This can clearly become a big maintenance burden, making it harder to keep the types in sync with the API and causing bugs to go unnoticed.

This is where Zimic comes in.

Zimic was designed to minimize these problems by providing a type-safe and ergonomic way to interact with HTTP APIs. One of the main concepts powering Zimic is the idea of a centralized schema, which serves as a source of truth for the structure of your HTTP endpoints. It is declared in a readable format and can be autogenerated from OpenAPI.

With Zimic, all requests, paths, parameters, and responses are type-checked using the schema, so that you can be confident that your code is communicating with the API correctly. This makes it easy to catch errors early in the development process without manually casting or checking types.

Since the schema is centralized and easy to understand, migrating to a new API version can be as simple as updating it and refactoring which parts of the codebase start reporting type errors. The schema can also type and validate your network mocks during testing, ensuring that your application, your tests, and your mocks are fully typed by default and in sync with the API.

Features

  • ⚙️ TypeScript-first

    Zimic has first-class TypeScript support, providing type safety, inference, validation, and autocompletion out of the box. "Typed by default" is one of the core principles of Zimic.

  • Lightweight

    The Zimic libraries are designed with minimal bundle sizes and few external dependencies in mind, making them perfect for both client and server-side applications.

  • 📦 Developer friendly

    We believe that developer experience is key to building great applications. The Zimic API strives to be as simple and intuitive as possible, and we're always looking for ways to improve it.

  • 🧪 Thoroughly tested

    Zimic has a comprehensive test suite and high code coverage. Testing is a main part of our development process, and we take reliability and developer confidence very seriously.

Ecosystem

Zimic is split into an ecosystem of integrated packages.

@zimic/http

A collection of type-safe utilities to handle HTTP requests and responses, including headers, search params, and form data.

Status: Beta 🌱
  • HTTP schemas

    Declare the structure of your endpoints in an HTTP schema and use it to type your HTTP requests and responses.

  • 💡 Type generation

    Infer types from OpenAPI documentation and generate ready-to-use HTTP schemas with our typegen CLI.

  • 📌 Type-safe APIs

    Declare typed Headers, URLSearchParams, and FormData objects, fully compatible with their native counterparts.

Learn more:

@zimic/fetch

A minimal (~2 kB minified and gzipped) and type-safe fetch-like API client.

Status: Beta 🌱
  • Type-safe fetch

    Use your @zimic/http schema to create a type-safe fetch-like API client and have your requests and responses fully typed by default.

  • Zero dependencies

    @zimic/fetch has no external dependencies, making it a lightweight and fast alternative to other HTTP clients.

  • 💪 Developer experience

    Define default options to apply to your requests, such as a base URL, headers, search parameters, and more. Inspect and modify requests and responses using onRequest and onResponse listeners.

Learn more:

@zimic/interceptor

A type-safe HTTP interceptor library for handling and mocking HTTP requests in development and testing.

Status: Beta 🌱
  • 🌐 HTTP interceptors

    Use your @zimic/http schema to declare local and remote HTTP interceptors. Mock external services and simulate success, loading, and error states with ease and type safety.

  • 🔗 Network-level interception

    @zimic/interceptor combines MSW and interceptor servers to handle real HTTP requests. From your application's point of view, the mocked responses are indistinguishable from the real ones.

  • 💡 Readability

    @zimic/interceptor was designed to encourage clarity and readability in your mocks. Use declarative assertions to verify that your application is making the expected requests and test with confidence.

Learn more:

TIP: @zimic/fetch and @zimic/interceptor work best together

@zimic/fetch and @zimic/interceptor are designed to work together, providing a seamless and type-safe experience for making and mocking HTTP requests. With that in mind, it's perfectly possible to use @zimic/interceptor with any HTTP client implementation, or @zimic/fetch with any HTTP mocking library. See our @zimic/fetch testing guide for more information.

Contributing

If you find an issue with this documentation of this project in general, feel free to open an issue. If you have a question, please open a discussion instead.

In case you are interested in contributing to Zimic, first of all, thank you! Check out or contributing guide to get started. Please create an issue or discussion before working on a new feature or bug fix. Let's make sure that your contribution is aligned with the project's goals and vision first!