[{"data":1,"prerenderedAt":246},["ShallowReactive",2],{"/2025/11/14-generate-api-call-with-orval-and-axios-from-openapi-schema":3},{"id":4,"title":5,"body":6,"date":237,"description":86,"extension":238,"meta":239,"navigation":240,"path":241,"robots":242,"seo":243,"stem":244,"__hash__":245},"posts/2025/11/14 generate-api-call-with-orval-and-axios-from-openapi-schema.md","14 Generate Api Call With Orval And Axios From Openapi Schema",{"type":7,"value":8,"toc":234},"minimark",[9,18,25,28,52,54,65,67,74,87,89,113,121,123,166,168,181,183,186,194,197,199,202,210,223],[10,11,13],"post-title",{":date":12},"date",[14,15,17],"h1",{"id":16},"generate-api-call-with-orval-and-axios-from-openapi-schema","Generate API Call with Orval and Axios from OpenAPI Schema",[19,20,21],"notes",{},[22,23,24],"p",{},"This is a repost from my old blog. First posted in 1/20/2020.",[26,27],"br",{},[22,29,30,31,39,40,51],{},"I have a project with .NET Core 9.0 backend and React frontend. With the built-in OpenAPI support via ",[32,33,38],"code",{"className":34},[35,36,37],"bg-gray-200","p-2","rounded"," Microsoft.AspNetCore.OpenApi",", it makes it so much easier to generate OpenAPI documents. For more information, visit ",[41,42,45],"span",{"className":43},[44],"text-blue-600",[46,47,48],"a",{"href":48,"rel":49},"https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/overview?view=aspnetcore-9.0",[50],"nofollow",".",[26,53],{},[22,55,56,57,64],{},"To automate the process, I want to generate the document after built. And that's pretty easy as well by following instructions in (Generate OpenAPI documents at build-time)",[41,58,60],{"className":59},[44],[46,61,62],{"href":62,"rel":63},"https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/aspnetcore-openapi?view=aspnetcore-9.0&tabs=visual-studio%2Cvisual-studio-code#generate-openapi-documents-at-build-time",[50]," article.",[26,66],{},[22,68,69,70,51],{},"In my csproj file, I put the following entries, so the Open API documents can be exported to a common location outside of the backend project directory with name ",[32,71,73],{"className":72},[35,36,37],"api.json",[75,76,77],"code-block",{},[78,79,84],"pre",{"className":80,"code":82,"language":83},[81],"language-text","\u003CPropertyGroup>\n  \u003COpenApiDocumentsDirectory>../../../openapi\u003C/OpenApiDocumentsDirectory>\n  \u003COpenApiGenerateDocumentsOptions>--file-name api\u003C/OpenApiGenerateDocumentsOptions>\n  ...\n\u003C/PropertyGroup>\n","text",[32,85,82],{"__ignoreMap":86},"",[26,88],{},[22,90,91,92,99,100,107,108,112],{},"On the frontend, I would like to automatically ingest that document and automatically generate code to make the api call. That's where Orval (",[41,93,95],{"className":94},[44],[46,96,97],{"href":97,"rel":98},"https://orval.dev/",[50],") comes in. Since I want to use custom Axios instance, I use the following guide: ",[41,101,103],{"className":102},[44],[46,104,105],{"href":105,"rel":106},"https://orval.dev/guides/custom-axios",[50],". My ",[32,109,111],{"className":110},[35,36,37],"orval.config.js"," looks like the following:",[75,114,115],{},[78,116,119],{"className":117,"code":118,"language":83},[81],"import { defineConfig } from 'orval';\n\nexport default defineConfig({\n  api: { //custom name, it can be any friendly name.\n    input: '../openapi/api.json',\n    output: {\n      mode: 'single',\n      target: 'src/api/api.ts',\n      schemas: 'src/api/model',\n      mock: false,\n      override: {\n        mutator: {\n          path: './src/services/axios-service.ts',\n          name: 'request'\n        }\n      }\n    }\n  }\n});\n",[32,120,118],{"__ignoreMap":86},[26,122],{},[22,124,125,126,130,131,135,136,143,144,148,149,153,154,158,159,51],{},"The ",[32,127,129],{"className":128},[35,36,37],"input"," is the path to the Open API document. Within output, ",[32,132,134],{"className":133},[35,36,37],"mode: Single"," tells Orval to generate a single file for all calls (usually one function per endpoint): ",[41,137,139],{"className":138},[44],[46,140,141],{"href":141,"rel":142},"https://orval.dev/reference/configuration/output#value-single",[50],". And ",[32,145,147],{"className":146},[35,36,37],"target"," is the output location and name of the generated code. While ",[32,150,152],{"className":151},[35,36,37],"schemas"," will hold the generated models/DTOs that represents request and response data. I just turn ",[32,155,157],{"className":156},[35,36,37],"mock"," to false since I don't use Faker at this time ",[41,160,162],{"className":161},[44],[46,163,164],{"href":164,"rel":165},"https://orval.dev/reference/configuration/output#mock",[50],[26,167],{},[22,169,170,171,175,176,180],{},"The override is where the interesting thing happen. In my case, it basically says, use the ",[32,172,174],{"className":173},[35,36,37],"request"," function in ",[32,177,179],{"className":178},[35,36,37],"./src/services/axios-service.ts"," to make the call.",[26,182],{},[22,184,185],{},"My axios-service.ts contains the following:",[75,187,188],{},[78,189,192],{"className":190,"code":191,"language":83},[81],"export const request = \u003CT>(\n    config: AxiosRequestConfig,\n    params?: Params\n  ): Promise\u003CT> => {\n    axiosInstance.defaults.baseURL = import.meta.env.VITE_BASE_URL;\n\n    const source = axios.CancelToken.source();\n    const axiosConfig: AxiosRequestConfig = {\n      ...config,\n      cancelToken: source.token,\n      headers: {\n        Authorization: `Bearer ${params?.accessToken}`\n      }\n    };\n    \n    const promise = axiosInstance(axiosConfig).then(({ data }) => data);\n\n    // @ts-ignore\n    promise.cancel = () => {\n      source.cancel('Query was cancelled');\n    };\n\n    return promise;\n  };\n",[32,193,191],{"__ignoreMap":86},[22,195,196],{},"This way, I use the BASE_URL specified in .env file so I can differentiate between local and remote environment. Also, I allow injection of access token, so my call can be authorized by the backend.",[26,198],{},[22,200,201],{},"Orval will then generate something similar to the following calls in api.ts:",[75,203,204],{},[78,205,208],{"className":206,"code":207,"language":83},[81],"options?: SecondParameter\u003Ctypeof request\u003CUserResponse>>,) => {\n      return request\u003CUserResponse>(\n      {url: `/users`, method: 'POST'\n    },\n      options);\n    }\n  \nexport const getCustomers = (\n    \n options?: SecondParameter\u003Ctypeof request\u003CCustomersResponse[]>>,) => {\n      return request\u003CCustomersResponse[]>(\n      {url: `/customers`, method: 'GET'\n    },\n      options);\n    }\n  \nexport const postCustomers = (\n    customersRequest: CustomersRequest,\n options?: SecondParameter\u003Ctypeof request\u003Cvoid>>,) => {\n      return request\u003Cvoid>(\n      {url: `/customers`, method: 'POST',\n      headers: {'Content-Type': 'application/json', },\n      data: customersRequest\n    },\n      options);\n    }\n",[32,209,207],{"__ignoreMap":86},[22,211,212,213,217,218,222],{},"In package.json, I added command to run orval during ",[32,214,216],{"className":215},[35,36,37],"npm run dev"," and ",[32,219,221],{"className":220},[35,36,37],"npm run build"," commands:",[75,224,225,228],{},[22,226,227],{},"\"scripts\": {\n\"dev\": \"orval && ...\",\n\"build\": \"orval && ...\",\n...\n}",[78,229,232],{"className":230,"code":231,"language":83},[81],"::\n\nThat way, when I run the frontend locally, it will generate the code using the latest document. It will also generate when run within CI/CD pipeline. It saves a lot of time by automatically modify the frontend code when the backend api changes.\n",[32,233,231],{"__ignoreMap":86},{"title":86,"searchDepth":235,"depth":235,"links":236},2,[],"2025-11-14T00:00:00.000Z","md",{},true,"/2025/11/14-generate-api-call-with-orval-and-axios-from-openapi-schema",null,{"title":5,"description":86},"2025/11/14 generate-api-call-with-orval-and-axios-from-openapi-schema","sUFER8OY5MfeD7M3EuHrqdkxDOgInkwSw_ShTP5PQXo",1785167452549]