{"id":16293585,"url":"https://github.com/badsyntax/openapi-dotnet-react-typescript-fetch-example","last_synced_at":"2025-03-20T03:31:09.395Z","repository":{"id":136895204,"uuid":"400404245","full_name":"badsyntax/openapi-dotnet-react-typescript-fetch-example","owner":"badsyntax","description":"An example project showing how to use the OpenAPI typescript-fetch HTTP client with React","archived":false,"fork":false,"pushed_at":"2021-10-17T05:32:35.000Z","size":446,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-28T22:55:08.110Z","etag":null,"topics":["openapi","openapi-generator","react","react-query","swagger","typescript"],"latest_commit_sha":null,"homepage":"https://richardwillis.info/blog/generate-a-type-script-http-client-from-an-open-api-spec-in-dot-net-5","language":"Mustache","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/badsyntax.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-27T05:57:03.000Z","updated_at":"2023-01-26T12:48:17.000Z","dependencies_parsed_at":"2023-04-14T01:30:52.735Z","dependency_job_id":null,"html_url":"https://github.com/badsyntax/openapi-dotnet-react-typescript-fetch-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsyntax%2Fopenapi-dotnet-react-typescript-fetch-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsyntax%2Fopenapi-dotnet-react-typescript-fetch-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsyntax%2Fopenapi-dotnet-react-typescript-fetch-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsyntax%2Fopenapi-dotnet-react-typescript-fetch-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/badsyntax","download_url":"https://codeload.github.com/badsyntax/openapi-dotnet-react-typescript-fetch-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244047647,"owners_count":20389206,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["openapi","openapi-generator","react","react-query","swagger","typescript"],"created_at":"2024-10-10T20:11:48.303Z","updated_at":"2025-03-20T03:31:09.388Z","avatar_url":"https://github.com/badsyntax.png","language":"Mustache","readme":"# openapi-dotnet-react-typescript-fetch-example\n\nAn example project that demonstrates how to:\n\n- Generate a typed HTTP client package from an OpenAPI definition using the [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) [`typescript-fetch`](https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/typescript-fetch.md) template\n- Consume the HTTP client in a React application using [react-query](https://github.com/tannerlinsley/react-query)\n\n## Project Overview\n\n```console\n├── HTTPClient/lib  # The generated typescript-fetch HTTP client\n├── ReactApp        # A TypeScript React front-end application that consumes the HTTP Client\n├── WebAPI          # A .NET 5 web API that provides the OpenAPI definitions\n```\n\n### Generating the HTTP Client\n\nThe following software is required:\n\n- [.NET 5.0](https://dotnet.microsoft.com/download/dotnet/5.0)\n- [Node.js 16](https://nodejs.org/)\n\nRun the folllowing to generate the client:\n\n```console\ndotnet tool restore\ndotnet msbuild -target:GenerateHTTPClient WebAPI -property:Configuration=Release\n```\n\nThe [build script](https://github.com/badsyntax/openapi-typescript-fetch-example/blob/1bc5fa198157f08ba4fe4cc61b276bc39d135dde/WebAPI/WebAPI.csproj#L12-L16) does the following:\n\n- Builds the WebAPI .NET application\n- Extracts the OpenAPI spec from the .NET application to location `./HTTPClient/api-spec.json`\n- Runs some `npm scripts` within `./HTTPClient` to generate the client (Refer to the scripts in [`./HTTPClient/package.json`](./HTTPClient/package.json))\n\n## Consuming the HTTP Client with React\n\n### API Setup\n\nAPI instances and react-query are setup within [./ReactApp/src/api](./ReactApp/src/api), for example:\n\n```ts\nimport {\n  Configuration,\n  ConfigurationParameters,\n  WeatherForecastApi,\n} from 'example-service-client';\nimport { ApiMiddleware } from './ApiMiddleware';\n\nconst configParams: ConfigurationParameters = {\n  basePath: 'https://localhost:5001',\n  middleware: [new ApiMiddleware()],\n};\n\nconst apiConfig = new Configuration(configParams);\n\nexport const apiClient = {\n  weatherForecastApi: new WeatherForecastApi(apiConfig),\n};\n\nexport type ApiClient = typeof apiClient;\n```\n\n### Query Hooks\n\n[Query hooks](./ReactApp/src/api/hooks/) call the generated HTTP Client methods, and support request cancellation, for example:\n\n```ts\nimport { WeatherForecast } from 'example-service-client';\nimport { useQuery, UseQueryOptions, UseQueryResult } from 'react-query';\nimport { ResponseError } from '../types';\nimport { withQueryCancellation } from '../util/withQueryCancellation';\nimport { useApiClient } from './useApiClient';\n\nexport const getWeatherForecastKey = 'getWeatherForecast';\n\nexport function useGetWeatherForecast(\n  options?: UseQueryOptions\u003cArray\u003cWeatherForecast\u003e, ResponseError\u003e\n): UseQueryResult\u003cArray\u003cWeatherForecast\u003e, ResponseError\u003e {\n  const { weatherForecastApi } = useApiClient();\n  return useQuery(\n    getWeatherForecastKey,\n    withQueryCancellation((signal) =\u003e\n      weatherForecastApi.weatherForecastGet({ signal })\n    ),\n    options\n  );\n}\n```\n\nQuery hooks are called in [React components](./ReactApp/src/App/App.tsx), for example:\n\n```tsx\nexport const App: React.FC = () =\u003e {\n  const queryClient = useQueryClient();\n\n  const {\n    data = [],\n    error,\n    isFetching,\n    refetch,\n  } = useGetWeatherForecast({\n    enabled: false,\n  });\n\n  const getWeatherForecast = () =\u003e {\n    if (!isFetching) {\n      refetch();\n    }\n  };\n\n  const cancelGetWeatherForecast = () =\u003e {\n    void queryClient.cancelQueries(getWeatherForecastKey);\n  };\n\n  return (\n    \u003cdiv className=\"App\"\u003e\n      \u003cbutton className=\"App-link\" onClick={getWeatherForecast}\u003e\n        Get Weather Forecast\n      \u003c/button\u003e\n      {isFetching \u0026\u0026 (\n        \u003cp\u003e\n          Loading...(\n          \u003cbutton className=\"App-link\" onClick={cancelGetWeatherForecast}\u003e\n            Cancel\n          \u003c/button\u003e)\n        \u003c/p\u003e\n      )}\n      {error \u0026\u0026 \u003cp\u003eError! {getResponseErrorMessage(error)}\u003c/p\u003e}\n      {data.map((forecast, i) =\u003e (\n        \u003cp key={i}\u003e\n          {forecast.summary} ({forecast.temperatureC}C)\n        \u003c/p\u003e\n      ))}\n    \u003c/div\u003e\n  );\n};\n```\n\n## Running the WebAPI\n\n```console\ndotnet run --project WebAPI\n```\n\nSwagger is then available at: \u003chttps://localhost:5001/swagger/index.html\u003e\n\n## Running the React App\n\n```console\nnpm start --prefix ReactApp\n```\n\n## How this project was bootstrapped\n\n```console\ndotnet new gitignore\ndotnet new tool-manifest\ndotnet new nugetconfig\ndotnet tool install Swashbuckle.AspNetCore.Cli\ndotnet new sln --name OpenAPITypeScriptFetchExample\ndotnet new webapi -o WebAPI\ndotnet sln add WebAPI\n\n# .editorconfig config manually created from https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options\n\nnpx create-react-app react-app --template typescript\nmv react-app ReactApp\n```\n\n## TODO\n\n- [ ] Add bearer token auth to .NET project\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadsyntax%2Fopenapi-dotnet-react-typescript-fetch-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbadsyntax%2Fopenapi-dotnet-react-typescript-fetch-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadsyntax%2Fopenapi-dotnet-react-typescript-fetch-example/lists"}