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.
-
⭐ 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
, andFormData
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.
-
⚡ Type-safe
fetch
Use your
@zimic/http
schema to create a type-safefetch
-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
andonResponse
listeners.
Learn more:
@zimic/interceptor
A type-safe HTTP interceptor library for handling and mocking HTTP requests in development and testing.
-
🌐 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:
@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!