{"id":13683736,"url":"https://github.com/contiamo/restful-react","last_synced_at":"2025-10-06T10:30:58.409Z","repository":{"id":37405931,"uuid":"139149148","full_name":"contiamo/restful-react","owner":"contiamo","description":"A consistent, declarative way of interacting with RESTful backends, featuring code-generation from Swagger and OpenAPI specs 🔥","archived":true,"fork":false,"pushed_at":"2023-02-03T22:49:48.000Z","size":9729,"stargazers_count":1868,"open_issues_count":53,"forks_count":109,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-01-14T18:43:27.502Z","etag":null,"topics":["openapi","openapi3","react","rest","swagger","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/contiamo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-29T12:52:25.000Z","updated_at":"2024-10-19T21:09:17.000Z","dependencies_parsed_at":"2023-02-18T11:48:37.956Z","dependency_job_id":null,"html_url":"https://github.com/contiamo/restful-react","commit_stats":null,"previous_names":[],"tags_count":106,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contiamo%2Frestful-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contiamo%2Frestful-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contiamo%2Frestful-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contiamo%2Frestful-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/contiamo","download_url":"https://codeload.github.com/contiamo/restful-react/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235519935,"owners_count":19003201,"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","openapi3","react","rest","swagger","typescript"],"created_at":"2024-08-02T13:02:27.477Z","updated_at":"2025-10-06T10:30:52.644Z","avatar_url":"https://github.com/contiamo.png","language":"TypeScript","readme":"# `restful-react`\n\n[![npm](https://img.shields.io/npm/v/restful-react.svg)](https://www.npmjs.com/package/restful-react)\n\n⚠️ **restful-react has been deprecated:** We are focusing on a new open api generator that generates `react-query` components: https://github.com/fabien0102/openapi-codegen ⚠️\n\nBuilding React apps that interact with a RESTful API presents a set of questions, challenges and potential gotchas. This project aims to remove such pitfalls, and provide a pleasant developer experience when crafting such applications.\n\nIt can be considered **a thin wrapper around the [fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API) in the form of React components and hooks.**\n\nWhen used in a setup with [OpenAPI / Swagger](https://en.wikipedia.org/wiki/OpenAPI_Specification) specs and [Typescript](https://www.typescriptlang.org/), **restful-react ensures a reliable and always up to date contract between backend and frontend.** It generates components and types from your specs and can be integrated quite comfortably into your development workflows (featuring for example the import of OpenAPI specs from your github repos).\n\nrestful-react is **very well tested, production ready** and powers all of our projects at Contiamo.\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Overview](#overview)\n- [Getting Started](#getting-started)\n- [Features](#features)\n  - [Global Configuration](#global-configuration)\n    - [`RestfulProvider` API](#restfulprovider-api)\n  - [Loading and Error States](#loading-and-error-states)\n  - [Lazy Fetching](#lazy-fetching)\n  - [Response Resolution](#response-resolution)\n  - [Debouncing Requests](#debouncing-requests)\n  - [TypeScript Integration](#typescript-integration)\n  - [Query Parameters](#query-parameters)\n  - [Mutations with `useMutate`](#mutations-with-usemutate)\n  - [Mocks](#mocks)\n  - [Polling with `Poll`](#polling-with-poll)\n    - [Long Polling](#long-polling)\n    - [Full `Poll` Component API](#full-poll-component-api)\n    - [Polling and Code Generation](#polling-and-code-generation)\n  - [Code Generation from OpenAPI / Swagger specs](#code-generation-from-openapi--swagger-specs)\n    - [Usage](#usage)\n    - [Validation of the OpenAPI specification](#validation-of-the-openapi-specification)\n    - [API Versioning](#api-versioning)\n    - [Import from URL](#import-from-url)\n    - [Import from GitHub](#import-from-github)\n    - [Transforming an Original Spec](#transforming-an-original-spec)\n    - [Advanced configuration](#advanced-configuration)\n      - [Config File Format](#config-file-format)\n      - [Config File Example](#config-file-example)\n      - [Custom generator](#custom-generator)\n      - [Only generating custom code (no react hooks/components)](#only-generating-custom-code-no-react-hookscomponents)\n- [Contributing](#contributing)\n  - [Code](#code)\n  - [How to publish to npm](#how-to-publish-to-npm)\n- [`@without-cli` npm package](#without-cli-npm-package)\n- [Next Steps](#next-steps)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Overview\n\nAt its core, `restful-react` exposes a [hook](https://reactjs.org/docs/hooks-intro.html), called `useGet`. This component retrieves data, either on mount or later, and then handles error states, loading states, and other cases for you. As such, you get a component that _gets stuff_ and then does stuff with it. Here's a quick overview what it looks like.\n\n[![Edit restful-react demos](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/restful-react-demos-vjets)\n\n```jsx\nimport React from \"react\";\nimport { useGet } from \"restful-react\";\n\nconst MyComponent = () =\u003e {\n  const { data: randomDogImage } = useGet({\n    path: \"https://dog.ceo/api/breeds/image/random\",\n  });\n\n  return \u003cimg alt=\"Here's a good boye!\" src={randomDogImage \u0026\u0026 randomDogImage.message} /\u003e;\n};\n\nexport default MyComponent;\n```\n\nand on React Native,\n[Edit restful-react basic demo on Expo](https://snack.expo.io/SJaSAj49r)\n\n```jsx\nimport { AppRegistry, Image } from \"react-native\";\nimport React from \"react\";\n\nimport { useGet } from \"restful-react\";\n\nconst App = () =\u003e {\n  const { data: randomDogImage } = useGet({\n    path: \"https://dog.ceo/api/breeds/image/random\",\n  });\n  return (\n    \u003c\u003e\n      {randomDogImage \u0026\u0026 (\n        \u003cImage\n          style={{ width: 250, height: 250 }}\n          source={{\n            uri: randomDogImage.message,\n          }}\n        /\u003e\n      )}\n    \u003c/\u003e\n  );\n};\n\nAppRegistry.registerComponent(\"react-native-app\", () =\u003e App);\n```\n\n## Getting Started\n\nTo install and use this library, install it by running `yarn add restful-react`, or `npm i restful-react --save` and you should be good to go. Don't forget to `import { useGet } from \"restful-react\"` or similar wherever you need it!\n\n## Features\n\n`restful-react` ships with the following features that we think might be useful.\n\n### Global Configuration\n\nREST API endpoints usually sit alongside a base, global URL. As a convenience, the `RestfulProvider` allows top-level configuration of your requests, that are then passed down the React tree to `useGet` hooks.\n\nConsider,\n\n[![Edit restful-react demos](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/restful-react-demos-vjets)\n\n```jsx\n// index.js\n\nimport React from \"react\";\nimport { RestfulProvider } from \"restful-react\";\n\nimport App from \"./App.jsx\";\n\nconst MyRestfulApp = () =\u003e (\n  \u003cRestfulProvider base=\"https://dog.ceo/api\"\u003e\n    \u003cApp /\u003e\n  \u003c/RestfulProvider\u003e\n);\n\nexport default MyRestfulApp;\n```\n\nMeanwhile, in `./App.jsx`,\n\n```jsx\n// App.jsx\n\nimport React from \"react\";\nimport { useGet } from \"restful-react\";\n\nconst MyComponent = () =\u003e {\n  const { data: randomDogImage } = useGet({\n    // Inferred from RestfulProvider in index.js\n    path: \"breeds/image/random\",\n  });\n\n  return \u003cimg alt=\"Here's a good boye!\" src={randomDogImage \u0026\u0026 randomDogImage.message} /\u003e;\n};\n\nexport default MyComponent;\n```\n\nNaturally, the request will be sent to the full path `https://dog.ceo/api/breeds/image/random`. The full API of the `RestfulProvider` is outlined below. Each configuration option is composable and _can be_ overridden by `Get` components further down the tree.\n\n#### `RestfulProvider` API\n\nHere's a full overview of the API available through the `RestfulProvider`, along with its defaults.\n\n```tsx\n// Interface\nexport interface RestfulReactProviderProps\u003cT = any\u003e {\n  /** The backend URL where the RESTful resources live. */\n  base: string;\n  /**\n   * The path that gets accumulated from each level of nesting\n   * taking the absolute and relative nature of each path into consideration\n   */\n  parentPath?: string;\n  /**\n   * A function to resolve data return from the backend, most typically\n   * used when the backend response needs to be adapted in some way.\n   */\n  resolve?: ResolveFunction\u003cT\u003e;\n  /**\n   * Options passed to the fetch request.\n   */\n  requestOptions?: ((url: string, method: string, requestBody?: string) =\u003e Partial\u003cRequestInit\u003e) | Partial\u003cRequestInit\u003e;\n  /**\n   * Trigger on each error.\n   * For `Get` and `Mutation` calls, you can also call `retry` to retry the exact same request.\n   * Please note that it's quite hard to retrieve the response data after a retry mutation in this case.\n   * Depending of your case, it can be easier to add a `localErrorOnly` on your `Mutate` component\n   * to deal with your retry locally instead of in the provider scope.\n   */\n  onError?: (err: any, retry: () =\u003e Promise\u003cT | null\u003e, response?: Response) =\u003e void;\n  /**\n   * Trigger on each request.\n   */\n  onRequest?: (req: Request) =\u003e void;\n  /**\n   * Trigger on each response.\n   */\n  onResponse?: (req: Response) =\u003e void;\n  /**\n   * Query parameters passed to each request.\n   */\n  queryParams?: { [key: string]: any };\n  /**\n   * Query parameter stringify options applied for each request.\n   */\n  queryParamStringifyOptions?: IStringifyOptions;\n}\n\n// Usage\n\u003cRestfulProvider\n  base=\"String!\"\n  resolve={data =\u003e data}\n  requestOptions={(url, method, requestBody) =\u003e ({ headers: { Authorization: authToken } })}\n/\u003e;\n```\n\nHere's some docs about the [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request) type of request options.\n\n### Loading and Error States\n\n`useGet` hooks return an object with loading and error states, to allow for state handling. Consider,\n\n[![Edit restful-react demos](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/restful-react-demos-vjets)\n\n```jsx\nimport React from \"react\";\nimport { useGet } from \"restful-react\";\n\nconst MyComponent = () =\u003e {\n  const { data: randomDogImage, loading } = useGet({\n    path: \"https://dog.ceo/api/breeds/image/random\",\n  });\n\n  return loading ? \u003ch1\u003eLoading...\u003c/h1\u003e : \u003cimg alt=\"Here's a good boye!\" src={randomDogImage.message} /\u003e;\n};\n\nexport default MyComponent;\n```\n\n### Lazy Fetching\n\nIt is possible to use a `useGet` hook and defer the fetch to a later stage. This is done with the `lazy` boolean property. This is great for displaying UI immediately, and then allowing parts of it to be fetched as a response to an event: like the click of a button, for instance. Consider,\n\n[![Edit restful-react demos](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/restful-react-demos-vjets)\n\n```jsx\nimport React from \"react\";\nimport { useGet } from \"restful-react\";\n\nconst MyComponent = () =\u003e {\n  const { data: randomDogImage, loading, refetch } = useGet({\n    path: \"https://dog.ceo/api/breeds/image/random\",\n    lazy: true,\n  });\n\n  return !randomDogImage \u0026\u0026 loading ? (\n    \u003ch1\u003eLoading!\u003c/h1\u003e\n  ) : (\n    \u003cdiv\u003e\n      \u003cdiv\u003e\n        \u003ch1\u003eWelcome to my image getter!\u003c/h1\u003e\n        \u003cbutton onClick={() =\u003e refetch()}\u003eGet a good boye!\u003c/button\u003e\n      \u003c/div\u003e\n      \u003cdiv\u003e{randomDogImage \u0026\u0026 \u003cimg alt=\"Here's a good boye!\" src={randomDogImage.message} /\u003e}\u003c/div\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default MyComponent;\n```\n\nThe above example will display your UI, and then load good boyes on demand.\n\n### Response Resolution\n\nSometimes, your backend responses arrive in a shape that you might want to adapt, validate, or restructure. Other times, maybe your data consistently arrives in a `{ data: {} }` shape, with `data` containing the stuff you want.\n\nAt the `RestfulProvider` level, _or_ on the `useGet` level, a `resolve` prop will take the data and _do stuff_ to it, providing the final resolved or unwrapped data to the children. Consider,\n\n[![Edit restful-react demos](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/restful-react-demos-vjets)\n\n```jsx\nimport React from \"react\";\nimport { useGet } from \"restful-react\";\n\nconst MyComponent = () =\u003e {\n  const { data: imageUrl } = useGet({\n    path: \"https://dog.ceo/api/breeds/image/random\",\n    resolve: image =\u003e image \u0026\u0026 image.message,\n  });\n\n  return imageUrl \u0026\u0026 \u003cimg alt=\"Here's a good boye!\" src={imageUrl} /\u003e;\n};\n\nexport default MyComponent;\n```\n\n### Debouncing Requests\n\nSome requests fire in response to a rapid succession of user events: things like autocomplete or resizing a window. For this reason, users sometimes need to wait until all the keystrokes are typed (until everything's _done_), before sending a request.\n\n`restful-react` exposes a `debounce` prop on `Get` that does exactly this.\n\nHere's an example:\n\n```jsx\nconst SearchThis = props =\u003e {\n  const { data } = useGet({\n    path: \"/hello/world\",\n    debounce: true,\n  });\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eHere's all the things I search\u003c/h1\u003e\n      \u003cul\u003e\n        {data.map(thing =\u003e (\n          \u003cli\u003e{thing}\u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\nDebounce also accepts a number, which tells `useGet` how long to wait until doing the request.\n\n```diff\nconst SearchThis = props =\u003e {\n  const { data } = useGet({\n    path: \"/hello/world\",\n-    debounce: true,\n+    debounce: 200 /* ms */,\n  })\n\n  return \u003cdiv\u003e\n        \u003ch1\u003eHere's all the things I search\u003c/h1\u003e\n        \u003cul\u003e\n          {data.map(thing =\u003e (\n            \u003cli\u003e{thing}\u003c/li\u003e\n          ))}\n        \u003c/ul\u003e\n      \u003c/div\u003e\n}\n```\n\nIt uses [lodash's debounce](https://lodash.com/docs/4.17.10#debounce) function under the hood, so you get all the benefits of it out of the box like so!\n\n```diff\n\nconst SearchThis = props =\u003e {\n  const { data } = useGet({\n    path: \"/hello/world\",\n-    debounce: 200,\n+    debounce: { wait: 200, options: { leading: true, maxWait: 300, trailing: false } } /* ms */,\n  })\n\n  return \u003cdiv\u003e\n        \u003ch1\u003eHere's all the things I search\u003c/h1\u003e\n        \u003cul\u003e\n          {data.map(thing =\u003e (\n            \u003cli\u003e{thing}\u003c/li\u003e\n          ))}\n        \u003c/ul\u003e\n      \u003c/div\u003e\n}\n```\n\n### TypeScript Integration\n\nOne of the most powerful features of `restful-react` is that each component exported is strongly typed, empowering developers through self-documenting APIs.\n\n![Using restful-react in VS Code](assets/labs.gif)\n\n### Query Parameters\n\nAll components in this library support query params (`https://my.site/?query=param`) via a `queryParams` prop. Each `useGet`, `useMutate` and `Poll` instance is _generic_, having a type signature of `useGet\u003cTData, TError, TQueryParams\u003e`. If described, the `queryParams` prop is _fully_ type-safe in usage and provides autocomplete functionality.\n\n![Autocompletion on QueryParams](assets/idp.gif)\n\nPlease note that the above example was built using our [OpenAPI generator](#code-generation) in order to infer the type of component from the specification and automatically generate the entire type-safe component in a _very_ quick and easy way.\n\n### Mutations with `useMutate`\n\n`restful-react` exposes an additional hook called `useMutate`. These components allow sending requests with other HTTP verbs in order to mutate backend resources.\n\n[![Edit restful-react demos](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/restful-react-demos-vjets)\n\n```jsx\nimport React from \"react\";\nimport { useGet, useMutate } from \"restful-react\";\n\nconst base = \"https://jsonplaceholder.typicode.com\";\n\nconst ListItem = ({ id, children }) =\u003e {\n  const { mutate: del, loading } = useMutate({\n    verb: \"DELETE\",\n    path: `/posts/`,\n    base,\n  });\n\n  return (\n    \u003cli key={id}\u003e\n      {loading ? (\n        \"Deleting...\"\n      ) : (\n        \u003cbutton onClick={() =\u003e del(id).then(() =\u003e alert(\"Deleted successfully. Pretend it got removed from the DOM.\"))}\u003e\n          ❌\n        \u003c/button\u003e\n      )}\n      \u0026nbsp;{children}\n    \u003c/li\u003e\n  );\n};\n\nconst MyHugeList = () =\u003e {\n  const { data: posts } = useGet({\n    path: \"/posts\",\n    base,\n  });\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003ePosts\u003c/h1\u003e\n      \u003cul\u003e\n        {posts \u0026\u0026\n          posts.map(post =\u003e (\n            \u003cListItem key={post.id} id={post.id}\u003e\n              {post.title}\n            \u003c/ListItem\u003e\n          ))}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n};\nexport default MyHugeList;\n```\n\n`useMutate` is strongly typed, and provides intelligent autocompletion out of the box, complete with other available [HTTP verbs](https://developer.mozilla.org/de/docs/Web/HTTP/Methods).\n\n![Mutate](assets/mutate.png)\n\nEach mutation returns a promise that can then be used to update local component state, dispatch an action, or do something else depending on your use case.\n\n### Mocks\n\nNo backend support yet for your amazing feature? Need to isolate an edge case? You can easily provide a mock to `useMutate` and `useGet` to bypass the classic flow.\n\n/!\\ If `mock` option is provided, no requests will be send to the server. /!\\\n\n```jsx\nimport React from \"react\";\nimport { useGet, useMutate } from \"restful-react\";\n\nconst base = \"https://jsonplaceholder.typicode.com\";\n\n// Mock the `mutate` handler\nconst { mutate: del, loading } = useMutate({\n  verb: \"DELETE\",\n  path: `/posts/`,\n  base,\n  // This will avoid any server call in favor of mock response\n  mock: {\n    mutate: id =\u003e console.log(`The item ${id} was deleted`),\n  },\n});\n\n// Mock the `loading`, so it's easy to isolate the loading state\nconst { data: posts } = useGet({\n  path: \"/posts\",\n  base,\n  // This will avoid any server call in favor of mock response\n  mock: {\n    loading: true,\n  },\n});\n\n// Mock the `error`, so it's easy to isolate the error state\nconst { data: posts } = useGet({\n  path: \"/posts\",\n  base,\n  // This will avoid any server call in favor of mock response\n  mock: {\n    error: \"oh no!\",\n  },\n});\n```\n\n### Polling with `Poll`\n\n`restful-react` also exports a `Poll` render props component that will poll a backend endpoint over a predetermined interval until a stop condition is met. Consider,\n\n```jsx\nimport { Poll } from \"restful-react\"\n\n\u003cPoll path=\"/deployLogs\" resolve={data =\u003e data \u0026\u0026 data.data}\u003e\n  {(deployLogs: DeployLog[], { loading }) =\u003e\n    loading ? (\n      \u003cPageSpinner /\u003e\n    ) : (\n      \u003cDataTable\n        columns={[\"createdAt\", \"deployId\", \"status\", \"sha\", \"message\"]}\n        orderBy=\"createdAt\"\n        data={deployLogs}\n        formatters={{\n          createdAt: (d: DeployLog[\"createdAt\"]) =\u003e title(formatRelative(d, Date.now())),\n          sha: (i: DeployLog[\"sha\"]) =\u003e i \u0026\u0026 i.slice(0, 7),\n        }}\n      /\u003e\n    )\n  }\n\u003c/Poll\u003e\n```\n\n`Poll` supports:\n\n- an `interval` prop that will poll at a specified interval (defaults to polling 1 second), and\n- an `until` prop that accepts a condition expressed as a function that returns a boolean value. When this condition is met, polling will stop.\n\n  The signature of this function is `(data: T, response: ResponseInit) =\u003e boolean`. As a developer, you have access to the returned data, along with the response object in case you'd like to stop polling if `response.ok === false`, for example.\n\nBelow is a more convoluted example that employs nearly the full power of the `Poll` component.\n\n```jsx\n\u003cPoll path=\"/status\" until={(_, response) =\u003e response \u0026\u0026 response.ok} interval={0} lazy\u003e\n  {(_, { loading, error, finished, polling }, { start }) =\u003e {\n    return loading ? (\n      \u003cProgress error={error} /\u003e\n    ) : (\n      \u003cButton\n        loading={editorLoading || polling}\n        condensed\n        icon=\"ExternalLink\"\n        color=\"ghost\"\n        onClick={() =\u003e {\n          if (finished) {\n            return window.open(editor.url);\n          }\n          requestEditor();\n          start();\n        }}\n      \u003e\n        {finished ? \"Launch Editor\" : \"Request Editor\"}\n      \u003c/Button\u003e\n    );\n  }}\n\u003c/Poll\u003e\n```\n\nNote from the previous example, `Poll` also exposes more states: `finished`, and `polling` that allow better flow control, as well as lazy-start polls that can also be programmatically stopped at a later stage.\n\n#### Long Polling\n\nAt Contiamo, we have a [powerful Long Polling specification](docs/contiamo-long-poll.md) in place that allows us to build real-time apps over HTTPS, as opposed to WebSockets. At a glance the specification can be distilled into:\n\n- Web UI sends a request with a `Prefer` header that contains:\n  - a time, in seconds, to keep requests open (`60s`), and\n  - a **polling index** that is a server-sent hash `ahpiegh`.\n  - all together, the client sends a request with a header `Prefer: wait=60s;index=939192`.\n- The backend server responds, either with:\n  - an empty response with status `304 Not Modified`\n  - a successful response with data and a new **polling index**.\n\nThe polling index allow the client and the server to stay in sync: the client says \"the last stuff I got was at this index\". The server says \"oh, let me get you up to speed and send you a new index\".\n\nVisually, this is represented as below.\n\n![Contiamo Poll](docs/long-poll-flow.png).\n\nTo get this functionality in `restful-react`, this means specifying a `wait` prop on your `Poll` component, provided your server implements this specification as well.\n\n#### [Full `Poll` Component API](src/Poll.tsx#L53-L101)\n\n#### Polling and Code Generation\n\nBy default we generate a `Poll` component when the `prefer` header is specified in the OpenAPI/Swagger specs (more information about this design decision here -\u003e https://github.com/contiamo/restful-react#long-polling).\n\nWe do not generate an equivalent hook version. Polling is quite trivial in a react hook, so we usually just use `useEffect` when we need some polling feature.\n\nExample:\n\n```ts\n// Poll data if no completedAt\nuseEffect(() =\u003e {\n  if (error) {\n    return onError();\n  } else if (data \u0026\u0026 !data.completedAt) {\n    const timerId = window.setTimeout(() =\u003e refetch(), 1000);\n    return () =\u003e window.clearTimeout(timerId);\n  } else {\n    return;\n  }\n}, [data, refetch, error]);\n```\n\n### Code Generation from OpenAPI / Swagger specs\n\n`restful-react` is able to generate React hooks with appropriate type-signatures (TypeScript) from any valid OpenAPI v3 or Swagger v2 specification, either in `yaml` or `json` formats.\n\n#### Usage\n\nType-safe React data fetchers can be generated from an OpenAPI specification using the following command:\n\n- `restful-react import --file MY_OPENAPI_SPEC.yaml --output my-awesome-generated-types.tsx`\n\nThis command can be invoked by _either_:\n\n- Installing `restful-react` globally and running it in the terminal: `npm i -g restful-react`, or\n- Adding a `script` to your `package.json` like so:\n\n```diff\n      \"scripts\": {\n        \"start\": \"webpack-dev-server\",\n        \"build\": \"webpack -p\",\n+       \"generate-fetcher\": \"restful-react import --file MY_SWAGGER_DOCS.json --output FETCHERS.tsx\"\n      }\n```\n\nYour components can then be generated by running `npm run generate-fetcher`. Optionally, we recommend linting/prettifying the output for readability like so:\n\n```diff\n      \"scripts\": {\n        \"start\": \"webpack-dev-server\",\n        \"build\": \"webpack -p\",\n        \"generate-fetcher\": \"restful-react import --file MY_SWAGGER_DOCS.json --output FETCHERS.tsx\",\n+       \"postgenerate-fetcher\": \"prettier FETCHERS.d.tsx --write\"\n      }\n```\n\n#### Validation of the OpenAPI specification\n\nTo enforce the best quality as possible of specification, we have integrated the amazing [OpenAPI linter from IBM](https://github.com/IBM/openapi-validator). We strongly encourage you to setup your custom rules with a `.validaterc` file, you can find all useful information about this configuration [here](https://github.com/IBM/openapi-validator/#configuration).\n\nTo activate this, add a `--validation` flag to your `restful-react` call.\n\n#### API Versioning\n\nThe generated file will include an exported constant `SPEC_VERSION` that will contain to the OpenAPI `info.version` property's value.\n\n#### Import from URL\n\nAdding the `--url` flag to `restful-react import` instead of using the `--file` flag will attempt to fetch the spec from that endpoint.\n\n- `restful-react import --url https://api.mine.com/openapi.json --output my-awesome-generated-types.tsx`\n\n#### Import from GitHub\n\nAdding the `--github` flag to `restful-react import` instead of using the `--file` flag allows us to **create React components from an OpenAPI spec _remotely hosted on GitHub._** \u003csup\u003e_(how is this real life_ 🔥 _)_\u003c/sup\u003e\n\nTo generate components from remote specifications, you'll need to follow the following steps:\n\n1.  Visit [your GitHub settings](https://github.com/settings/tokens).\n1.  Click **Generate New Token** and choose the following:\n\n        Token Description: (enter anything)\n        Scopes:\n            [X] repo\n                [X] repo:status\n                [X] repo_deployment\n                [X] public_repo\n                [X] repo:invite\n                [X] security_events\n\n1.  Click **Generate token**.\n1.  Copy the generated string.\n1.  Open a terminal and run `restful-react import --github username:repo:branch:path/to/openapi.yaml --output MY_FETCHERS.tsx`, substituting things where necessary.\n1.  You will be prompted for a token.\n1.  Paste your token.\n1.  You will be asked if you'd like to save it for later. This is _entirely_ up to you and completely safe: it is saved in your home directory.\n1.  You're done! 🎉\n\nNote: For CI environment, you can also provide the github token with the environment variable called `GITHUB_TOKEN`\n\n#### Transforming an Original Spec\n\nIn some cases, you might need to augment an existing OpenAPI specification on the fly, for code-generation purposes. Our CLI makes this quite straightforward:\n\n```bash\n  restful-react import --file myspec.yaml --output mybettercomponents.tsx --transformer path/to/my-transformer.js\n```\n\nThe function specified in `--transformer` is pure: it imports your `--file`, transforms it, and passes the augmented OpenAPI specification to `restful-react`'s generator. Here's how it can be used:\n\n```ts\n// /path/to/my-transformer.js\n\n/**\n * Transformer function for restful-react.\n *\n * @param {OpenAPIObject} schema\n * @return {OpenAPIObject}\n */\nmodule.exports = inputSchema =\u003e ({\n  ...inputSchema,\n  // Place your augmentations here\n  paths: Object.entries(schema.paths).reduce(\n    (mem, [path, pathItem]) =\u003e ({\n      ...mem,\n      [path]: Object.entries(pathItem).reduce(\n        (pathItemMem, [verb, operation]) =\u003e ({\n          ...pathItemMem,\n          [verb]: {\n            ...fixOperationId(path, verb, operation),\n          },\n        }),\n        {},\n      ),\n    }),\n    {},\n  ),\n});\n```\n\n#### Advanced configuration\n\n`restful-react` supports the concept of \"schema stitching\" in a RESTful ecosystem as well. We are able to tie multiple backends together and generate code using a single configuration file, `restful-react.config.js`\n\nTo activate this \"advanced mode\", replace all flags from your `restful-react` call with the config flag: `--config restful-react.config.js` (or any filename that you want).\n\n⚠️ **Note:** using a config file makes use of all of the options contained therein, and ignores all other CLI flags.\n\n##### Config File Format\n\n```ts\ninterface RestfulReactConfig {\n  [backend: string]: {\n    // classic configuration\n    output: string;\n    file?: string;\n    github?: string;\n    transformer?: string;\n    validation?: boolean;\n    skipReact?: boolean;\n\n    // advanced configuration\n    customImport?: string;\n    customProps?: {\n      base?: string;\n    };\n    pathParametersEncodingMode?: \"uriComponent\" | \"rfc3986\";\n    customGenerator?: (data: {\n      componentName: string;\n      verb: string;\n      route: string;\n      description: string;\n      genericsTypes: string;\n      operation: OperationObject;\n      paramsInPath: string[];\n      paramsTypes: string;\n    }) =\u003e string;\n  };\n}\n```\n\n##### Config File Example\n\n```js\n// restful-react.config.js\n/**\n * Restful-react configuration.\n *\n * @type {import(\"restful-react/dist/bin/config\").RestfulReactAdvancedConfiguration}\n */\nmodule.exports = {\n  myFirstBackend: {\n    output: \"src/queries/myFirstBackend.tsx\",\n    file: \"specs/my-first-backend.yaml\",\n    customProps: {\n      base: `\"http://my-first-backend.com\"`,\n    },\n  },\n  configurableBackend: {\n    output: \"src/queries/configurableBackend.tsx\",\n    github: \"contiamo:restful-react:master:docs/swagger.json\",\n    customImport: `import { getConfig } from \"../components/Config.tsx\";`,\n    customProps: {\n      base: `{getConfig(\"backendBasePath\")}`,\n    },\n  },\n};\n```\n\n```json\n// package.json\n{\n  \"scripts\": {\n    \"gen\": \"restful-react import --config restful-react.config.js\",\n    \"gen-first\": \"restful-react import --config restful-react.config.js myFirstBackend\"\n  }\n}\n```\n\n##### Custom generator\n\nTo support even more advanced usecases (like a promise base API, mock generator or anything else that can infer from your specs), you can define your own template in `customGenerator`. This function will be call for each route with some useful computed values (see the types above) and the resulted string will be added to the generated file.\n\nYou can see a concrete usage inside the `examples` folder and try yourself in this repository with the following command:\n\n- `yarn build`\n- `yarn example:advanced petstore-custom-fetch`\n\nYou can inspect the result inside `/examples/petstoreFromFileSpecWithCustomFetch.tsx`\n\n##### Only generating custom code (no react hooks/components)\n\nIn some cases you might want to use the familiar restful-react to generate code for non-react environments (e.g. promise-based fetchers for nodejs or other frameworks). In this case, you can disable react code generation altogether by passing the `--skipReact` flag or, if you are using a configuration file, setting `skipReact: true`.\n\nWhen set, only your custom generators will be executed.\n\n## Contributing\n\nAll contributions are welcome – especially:\n\n- documentation,\n- bug reports and issues,\n- code contributions.\n\n### Code\n\nIf you'd like to actively develop or help maintain this project then there are existing tests against which you can test the library with. Typically, this looks like\n\n- `git clone git@github.com:contiamo/restful-react.git`\n- `cd restful-react`\n- `yarn install`\n- `yarn test --watch`\n\nFrom there, you should be able to start developing without problems.\n\n### How to publish to npm\n\nJust update the `version` in `package.json`!\n\nAs soon as your branch will be merged to master, a new npm version will be automatically published for you.\n\n## `@without-cli` npm package\n\nIf for any reasons you don't want to use our CLI to generate restful-react components, we provide a `without-cli` version of the package.\n\nJust `npm install restful-react@without-cli` to have this light version.\n\nThis version will follow `latest` but without the cli part (more details into `publish-without-cli.js`).\n\n## Next Steps\n\nWe're actively developing this at Contiamo to meet our use cases as they arise. If you have a use case that you'd like to implement, do it! Open an issue, submit a Pull Request, have fun! We're friendly.\n","funding_links":[],"categories":["TypeScript","Libraries"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontiamo%2Frestful-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcontiamo%2Frestful-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontiamo%2Frestful-react/lists"}