Node.js library that generates React Hooks based on the OpenAPI specification.
This project is a fork of openapi-typescript-codegen, which:
- Generates React hooks for OpenAPI specification, which is driven by jotai;
- Fixed many bugs in the schema generator, which could help us generate ajv-compliant JSON Schema;
- Add client-side type validation to enhance the robustness of your website;
- Dropped the support of OpenAPI v2 and XHR mode;
- Supports React Native.
npm install @jbcz/openapi-hooks-codegen --save-dev
Notice: React Native users may need react-native-url-polyfill
to get the support of baseUrl configuration, please check out the documentation.
$ openapi --help
Usage: openapi [options]
Options:
-V, --version output the version number
-i, --input <value> OpenAPI specification, can be a path, url or string content (required)
-o, --output <value> Output directory (required)
Examples
$ openapi --input ./spec.json
$ openapi --input ./spec.json --output ./dist
package.json
{
"scripts": {
"generate": "openapi --input ./spec.json --output ./dist"
}
}
Node.js API
const OpenAPI = require('openapi-hooks-codegen');
OpenAPI.generate({
input: './spec.json',
output: './dist'
});
// Or by providing the content of the spec directly 🚀
OpenAPI.generate({
input: require('./spec.json'),
output: './dist'
});
Basic usage
import { useGetRole } from './api';
const [role, roleController] = useGetRole();
roleController.fetchData(1);
Side effect
Like setting localStorage
after a login request.
import { useGetRole } from './api';
const [role, roleController] = useGetRole();
roleController.fetchData(1, {}, (atom, set, result) => {
set({ ...atom, data: result.body });
localStorage.setItem('token', result.body);
});
Credential
import { useGetRole, globalOptionsAtom } from './api';
const [role, roleController] = useGetRole();
const [globalConfig, setGlobalConfig] = useAtom(globalOptionsAtom)
setGlobalConfig({
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
},
});
roleController.fetchData(1);
Request body of a post request
import { useCreateRole } from './api';
const [role, createRoleController] = useCreateRole();
createRoleController.fetchData({
name: 'xxx',
permissions: ['xxx'],
// ...
});
Request header of a request
import { useGetRole } from './api';
const [role, roleController] = useGetRole();
roleController.fetchData(1, {
headers: {
'YourHeader': `YourValue`,
// ...
},
});
Infinite scrolling
import { useGetRole } from './api';
const [role, roleController] = useGetRole();
roleController.fetchData(1, {}, (atom, set, result) => {
set({
...atom,
data: atom.data.concat(result),
})
});
If your team is using Gitea / GitHub and want to automatically sync the spec with the repository, you can use the following project setup:
- Installing some dependencies:
yarn add -D npm-run-all dotenv-cli @jbcz/openapi-hooks-codegen
- Creating a
.env.openapi
file in the root directory of your project, with the following content:
GITEA_TOKEN=YOUR_SUPER_SECRET_TOKEN
GITHUB_TOKEN=YOUR_SUPER_SECRET_TOKEN
You can get your token from:
- Gitea: https://[GITEA_INSTANCE_URL]/user/settings/applications
- GitHub: https://github.com/settings/tokens
- Adding the following configuration to the
scripts
section of yourpackage.json
file:
"scripts": {
"sync-spec": "dotenv -e /env.openapi -- openapi-sync-gitea --ref RELEASE_TAG --owner REPO_OWNER --repo REPO_ID --filePath FILE_PATH_IN_THE_REPO --host GITEA_HOST -o ./spec.yaml",
"gen-api": "openapi --input ./spec.yaml --output ./src/api/",
"postinstall": "npm-run-all sync-spec gen-api",
},
openapi-sync-gitea
could be replaced to openapi-sync-github
, in case you are using
self hosted GitHub for Enterprise, the --host
can be customized, and default value is
set to api.github.com
.
-
Creating a
.gitkeep
file in the./src/api/
. -
IMPORTANT: Add the following configuration to your
.gitignore
file:
/env.openapi
/spec.yaml
/src/api/
!/src/api/.gitkeep
- Edit
tsconfig.json
to add the following configuration:
{
"compilerOptions": {
"baseUrl": "src",
}
}
- Run
yarn postinstall
to generate the API.
If you use enums inside your models/definitions then those enums are by default inside a namespace with the same name
as your model. This is called declaration merging. However, the @babel/plugin-transform-typescript
does not support these namespaces, so if you are using babel in your project please use the --useUnionTypes
flag
to generate union types instead of traditional enums. More info can be found here: Enums vs. Union Types.
Note: If you are using Babel 7 and Typescript 3.8 (or higher) then you should enable the onlyRemoveTypeImports
to
ignore any 'type only' imports, see https://babeljs.io/docs/en/babel-preset-typescript#onlyremovetypeimports for more info
module.exports = {
presets: [
['@babel/preset-typescript', {
onlyRemoveTypeImports: true,
}],
],
};