Inspired by [restful-react](https://github.com/contiamo/restful-react)
orval
is able to generate axios client with appropriate type-signatures (TypeScript) from any valid OpenAPI v3 or Swagger v2 specification, either in yaml
or json
formats.
Type-safe data fetchers can be generated from an OpenAPI specification using the following command:
orval import --file MY_OPENAPI_SPEC.yaml --output my-awesome-generated-types.tsx
This command can be invoked by either:
- Installing
orval
globally and running it in the terminal:npm i -g orval
, or - Adding a
script
to yourpackage.json
like so:
"scripts": {
"start": "webpack-dev-server",
"build": "webpack -p",
+ "generate-fetcher": "orval import --file MY_SWAGGER_DOCS.json --output FETCHERS.tsx"
}
Your client can then be generated by running npm run generate-fetcher
. Optionally, we recommend linting/prettifying the output for readability like so:
"scripts": {
"start": "webpack-dev-server",
"build": "webpack -p",
"generate-fetcher": "orval import --file MY_SWAGGER_DOCS.json --output FETCHERS.tsx",
+ "postgenerate-fetcher": "prettier FETCHERS.d.tsx --write"
}
To enforce the best quality as possible of specification, we have integrated the amazing OpenAPI linter from IBM. We strongly encourage you to setup your custom rules with a .validaterc
file, you can find all useful information about this configuration here.
To activate this, add a --validation
flag to your orval
call.
Adding the --github
flag to orval import
instead of using the --file
flag allows us to create your client from an OpenAPI spec remotely hosted on GitHub. (how is this real life 🔥 )
To generate components from remote specifications, you'll need to follow the following steps:
-
Visit your GitHub settings.
-
Click Generate New Token and choose the following:
Token Description: (enter anything) Scopes: [X] repo [X] repo:status [X] repo_deployment [X] public_repo [X] repo:invite
-
Click Generate token.
-
Copy the generated string.
-
Open a terminal and run
orval import --github username:repo:branch:path/to/openapi.yaml --output MY_FETCHERS.tsx
, substituting things where necessary. -
You will be prompted for a token.
-
Paste your token.
-
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
node_modules
folder and not committed to version control or sent to us or anything: the source code of this whole thing is public so you're safe.Caveat: Since your token is stored in
node_modules
, your token will be removed on eachnpm install
oforval
. -
You're done! 🎉
In some cases, you might need to augment an existing OpenAPI specification on the fly, for code-generation purposes. Our CLI makes this quite straightforward:
orval import --file myspec.yaml --output mybettercomponents.tsx --transformer path/to/my-transformer.js
The function specified in --transformer
is pure: it imports your --file
, transforms it, and passes the augmented OpenAPI specification to orval
's generator. Here's how it can be used:
// /path/to/my-transformer.js
/**
* Transformer function for orval.
*
* @param {OpenAPIObject} schema
* @return {OpenAPIObject}
*/
module.exports = inputSchema => ({
...inputSchema,
// Place your augmentations here
paths: Object.entries(schema.paths).reduce(
(mem, [path, pathItem]) => ({
...mem,
[path]: Object.entries(pathItem).reduce(
(pathItemMem, [verb, operation]) => ({
...pathItemMem,
[verb]: {
...fixOperationId(path, verb, operation)
}
}),
{}
)
}),
{}
)
});
orval
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, orval.config.js
To activate this "advanced mode", replace all flags from your orval
call with the config flag: --config orval.config.js
(or any filename that you want).
interface RestfulClientConfig {
[backend: string]: {
// path or output options object
output?: string | OutputOptions;
// path, url, or input options object
input?: string | InputOptions;
};
}
interface InputOptions = {
// path or url to the openapi spec
target?: string;
// validation of your openapi spec
validation?: boolean;
// override the input that's give you the possibility to add whatever you want to your openapi spec
override?: OverrideInput;
};
interface OutputOptions = {
// path to the file which will contains the implementation
target?: string;
// path to the directory or file that will contains your models (if not define the target will contains the models)
schemas?: string;
// add mock to your implementation
mock?: boolean;
// override the output like your mock implementation or transform the api implementation like you want
override?: OverrideOutput;
};
// orval.config.js
module.exports = {
'petstore-file': {
input: 'examples/petstore.yaml',
output: 'examples/petstoreFromFileSpecWithConfig.ts'
},
'petstore-file-transfomer': {
output: {
target: 'examples/petstoreFromFileSpecWithTransformer.ts',
schemas: 'examples/model',
mock: true
},
input: {
target: 'examples/petstore.yaml',
transformer: 'examples/transformer-add-version.js'
},
override: {
// contains operationId of your spec with override options
operations: {
listPets: {
// transform the output of your api call
transformer: 'examples/transformer-response-type.js',
mock: {
// override mock properties
properties: () => {
return {
id: faker.random.number({min: 1, max: 9})
};
}
}
},
showPetById: {
mock: {
// override mock for this api call
data: () => ({
id: faker.random.number({min: 1, max: 99}),
name: faker.name.firstName(),
tag: faker.helpers.randomize([faker.random.word(), undefined])
})
}
}
},
mock: {
// override mock properties for all api calls
properties: {
'/tag|name/': 'jon'
}
}
}
}
};
// package.json
{
"scripts": {
"gen": "orval import --config orval.config.js",
"gen-first": "orval import --config orval.config.js myFirstBackend"
}
}