Orval is Awesome

Published Mon Jan 15 2024

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:


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:

    summary: List all pets
    operationId: listPets
      - name: limit
        in: query
        description: How many items to return at one time (max 100)
        required: false
          type: string
          description: A paged array of pets
              description: A link to the next page of responses
                type: string
                  type: array
                    type: object
                          type: integer
                          format: int64
                          type: string
                            - 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' }]


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(
        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.