Orval is a REST API client generator for JavaScript and TypeScript. Orval is great because it is simple, uses an open industry standard (OpenAPI), and has broad tooling support. This allows it to serve it's purpose without making any tooling choices for you. To illustrate the benefits I will show you a simplified code sample from Orval's repo:
Input
When using Orval, you need to provide 2 things: an Orval configuration file and a valid OpenAPI spec. Here is a simplified YAML description of an endpoint Orval could consume:
/pets : get : summary : List all pets operationId : listPets parameters : - name : limit in : query description : How many items to return at one time (max 100) required : false schema : type : string responses : '200' : description : A paged array of pets headers : x-next : description : A link to the next page of responses schema : type : string content : application/json : schema : Pets : type : array items : type : object fields: id: type: integer format: int64 name: type: string required: - id - name
The specification has a lot of details, but for us the most important are:
- Path:
/pets - HTTP Method:
GET - A query parameter named
limit - The expected shape of a successful response
[{ id: 123, name: 'Winston' }]
Output
With this information Orval will generate some great boilerplate code to help kick start your API integration. Let's take a look at what is generated for react-query with the above spec:
/** * @summary List all pets */export const listPets = ( params ?: ListPetsParams , options ? : AxiosRequestConfig ) : Promise < AxiosResponse < unknown >> => { return axios . get ( `/pets` ,{ ...options , params : { ... params , ... options ?. params },} );
First we have a function listPets that calls axios with the specified path of /pets. This bit of code is helpful, but not exactly a game changer. It will be used in Orval's later react-query code.
export const getListPetsQueryKey = ( params ?: ListPetsParams ,) => { return [ `/pets` , ... ( params ? [ params ] : [])] as const ; }
Next is a function for creating a query key. This is important for integrating with react-query where each request is cached and accessible using a unique query key. Since our endpoint has a query parameter, Orval has included params in the key so that requests with different parameters are cached separately!
/** * @summary List all pets */export const useListPets = < TData = Awaited < ReturnType < typeof listPets >> , TError = AxiosError < unknown >> ( params ?: ListPetsParams , options ?: { query ?: UseQueryOptions < Awaited < ReturnType < typeof listPets >> , TError , TData > , axios ?: AxiosRequestConfig } ) : UseQueryResult < TData , TError > & { queryKey : QueryKey } => { const queryOptions = getListPetsQueryOptions ( params , options ) const query = useQuery ( queryOptions ) as UseQueryResult < TData , TError > & { queryKey : QueryKey }; query . queryKey = queryOptions . queryKey ; return query ; }
With the two previous generated functions Orval assembles a custom React hook for each endpoint when targeting react-query. The resulting function useListPets can be easily imported and called within a React component now, where you get immediate access to type safety provided by Orval and async query state provided by react-query! I have posted the code referenced here on my GitHub.
Wrapping Up
Orval provides useful code generation for familiar tools, once you are generating API client code you can try using their faker and MSW integrations to streamline testing as well. Since many APIs today are documented using OpenAPI your integration may be minutes away! If your API is currently undocumented, the benefits of Orval may help push you or your organization to begin documenting with OpenAPI.