DEV Community

Cover image for Zodios : an open source HTTP client with type checking at both compile time and runtime (part 1/3)
ecyrbe
ecyrbe

Posted on • Updated on

Zodios : an open source HTTP client with type checking at both compile time and runtime (part 1/3)

You might be familiar zod. It's a schema validation library like many others, that allows you to validate data from user inputs or network request.

The bonus you get from zod compared with the other similar libraries is that it's made from the ground up to use typescript, so it's one of the best to infer your typescript types and not duplicate declarations.

Indeed, with other libraries, you might have to declare your types with typescript and your schema with your validation library.

With zod, you only have to do it once :

const user = z.object({
  id: z.number(),
  type_of: z.string(),
  name: z.string(),
  username: z.string(),
});
type User = = z.infer<typeof user>;
/* same as */
type User = {
  id: number;
  type_of: string;
  name: string;
  username: string;
};
Enter fullscreen mode Exit fullscreen mode

Zodios

Zodios is a small open-source library that helps you declare your REST APIs in frontend applications thanks to Zod library.

You might be wondering why would you use another library since you might already be using fetch or axios to make your api requests.

Indeed, both allow you to make your API calls. But maybe some of you are experiencing the same issues all the time. You might need to :

  • Validate your API results and have to write both your types and schemas,
  • Have autocompletion and end-up using client api code generators like swagger editor client generator.

Zodios was made to address both these uses cases without having to rely on third party code generators that might produce unmaintainable code.

A basic example :

Before diving into more complex example in the second part of this article, here is a simple one.

We want to call the excellent jsonplaholder service to get all it's users and be able to filter the result with raw text search.

The endpoint we want to call : https://jsonplaceholder.typicode.com/users?q=ell
And here is how you would declare everything with zodios :

const apiClient = new Zodios(
  "https://jsonplaceholder.typicode.com",
  // API definition
  [
    {
      method: "get",
      path: "/users",
      description: "Get all users",
      parameters: [
        {
          name: "q",
          description: "full text search in users",
          type: "Query",
          schema: z.string(),
        },
      ],
      response: z.object({
        id: z.number(),
        name: z.string(),
        email: z.string(),
        address: z.object({
          street: z.string(),
          suite: z.string(),
          city: z.string(),
          zipcode: z.string(),
          geo: z.object({
            lat: z.string(),
            lng: z.string()
          }),
      }),
    },
  ] as const,
);
const users = await apiClient.get("/users", { queries: { q: "ell" } });
console.log(users);
Enter fullscreen mode Exit fullscreen mode

We see that we created a new instance of Zodios and we provided to it:

  • the base URL of jsonplaceholder
  • a user API declaration with something looking a lot like a schema or model declaration, but instead of using openapi json schema, we used zod syntax.

We then called this instance like we almost would with axios.
But what Zodios gives you with this schema declaration, is autocompletion and types with typescript out of the box.

Indeed, if you hover your mouse over the users variable in your typescript IDE, you'll get this :

const users: {
  id: string;
  name: string;
  email: string;
  address: {
    street: string;
    suite: string;
    city: string;
    zipcode: string;
    geo: {
      lat: string;
      lng: string;
    };
  };
}[]
Enter fullscreen mode Exit fullscreen mode

Your IDE just infered the types based on Zodios API declaration.

You'll also get autocompletions for all the parameters of the API telling you to provide in queries the q : string property.

Behind the scene, zodios is using Zod type inference and some custom typescript utility types.

Conclusion

Like many tools, this solution might not please everyone needs. Some might still prefer code generation tools to handle client API generation.

Zodios has the advantage of letting you in control with minimum boilerplate.

In the next articles, we will see :

  • How to declare alias endpoints
  • How to declare CRUD endpoints easily
  • How to handle large APIs declarations (like the one of dev.to).
  • How to split zod declarations and API declarations into multiple files.

You can see the example we'll talk about here

Top comments (0)

Some comments have been hidden by the post's author - find out more