Zodios : an open source HTTP client with type checking at both compile time and runtime (part 1/3)
Tags: typescript, axios, zodios, tutorial
Published: 2022-02-20 00:23:25

You might be familiar [zod](https://github.com/colinhacks/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 :

```typescript
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;
};
```

## Zodios

[Zodios](https://github.com/ecyrbe/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](https://jsonplaceholder.typicode.com/) 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](https://jsonplaceholder.typicode.com/users?q=ell)
And here is how you would declare everything with zodios :
```typescript
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);
```

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 :
```typescript
const users: {
  id: string;
  name: string;
  email: string;
  address: {
    street: string;
    suite: string;
    city: string;
    zipcode: string;
    geo: {
      lat: string;
      lng: string;
    };
  };
}[]
```
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](https://github.com/colinhacks/zod#type-inference) and some custom typescript [utility types](https://github.com/ecyrbe/zodios/blob/main/src/utils.types.ts).

## 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](https://github.com/ecyrbe/zodios/tree/main/examples/dev.to)