Use the OpenAPI Generator to Generate Typed Clients
REST is a common pattern to define APIs of services. Many SAP systems like SAP S/4HANA, SAP Concur and SAP Business Technology Platform provide their services through REST APIs. A common way to specify these services are OpenAPI specifications.
With the SAP Cloud SDK, you can generate typed clients for those specifications.
Check this guide for downloading a specification from SAP Business Accelerator Hub.
Installation
Run the command below to install the OpenAPI generator as a devDependency
:
npm install -D @sap-cloud-sdk/openapi-generator
Generate a Client Using the Command Line Interface
The SAP Cloud SDK generator is primarily intended to be used on the command line. You can generate an OpenAPI client by running:
npx openapi-generator --input <input> --outputDir <outputDirectory>
The <input>
points to your specification file or a directory containing the specification(s) and <outputDirectory>
to the target folder where the generated client(s) will be saved.
By default, the generated clients will each contain:
- API files as
.ts
files - one for each "API" in the service. See details. - A schema directory, containing schema files (
.ts
), one for each schema defined in the service specification. - All of the above as transpiled sources, including JavaScript sources (
.js
), type definition files (.d.ts
) and sourcemap files (.js.map
). - A
package.json
. - A
tsconfig.json
.
The generation always includes the TypeScript sources. All other files can be excluded from the generation - see the options below.
The generator should be installed as a local dependency, because global installations hide the used generator version and cause problems when transpiling to JavaScript.
If you must use a globally installed generator, install the @types/node
and @sap-cloud-sdk/openapi
package in your project to make the transpilation work.
If you need to transpile sources without any local node_modules
, you must manually execute the tsc
compiler on your own with a custom path mapping.
See transpile for more details in the options below.
Options
Run openapi-generator --help
for additional options.
Option | Default | Description |
---|---|---|
-i ,--input (required) | - | Specify the path to the directory or file containing the OpenAPI service definition(s) to generate clients for. Accepts Swagger and OpenAPI definitions as YAML and JSON files. Throws an error if the path does not exist. |
-o ,--outputDir (required) | - | Specify the path to the directory to generate the client(s) in. Each client is generated into a subdirectory within the given output directory. Creates the directory if it does not exist. Customize subdirectory naming through --optionsPerService . |
--optionsPerService | - | Set the path to a file containing the options per service. The configuration allows to set a directoryName and packageName for every service, identified by the path to the original file. It also makes sure that names do not change between generator runs. If a directory is passed, an options-per-service.json file is read/created in this directory. |
--overwrite | false | Allow overwriting files, that already exist. This is useful, when running the generation regularly. |
--clearOutputDir | false | Remove all files in the output directory before generation. Be cautious when using this option, as it really removes EVERYTHING in the output directory. |
--packageJson | false | When enabled, a package.json , that specifies dependencies and scripts for transpilation and documentation generation is generated. |
--include | '' | Include files matching the given glob into the root of each generated client directory. |
-t , --transpile , | false | Transpile the generated TypeScript code. When enabled a default tsconfig.json will be generated and used. It emits .js , .js.map and .d.ts files. To configure transpilation set --tsconfig . |
--tsconfig | default tsconfig | Replace the default tsconfig.json by passing a path to a custom configuration. By default, a tsconfig.json is only generated when transpilation is enabled (--transpile ). If a directory is passed, a tsconfig.json file is read from this directory. |
-p , --prettierConfig | default prettier config | Configuration file for prettier if you want to change the default value. |
--verbose | false | Turn on verbose logging. |
--skipValidation | false | By default, the generation fails, when there are duplicate or invalid names for operations and/or path parameters after transforming them to camel case. Set this to true to enable unique and valid name generation. The names will then be generated by appending numbers and prepending prefixes. |
-c , --config | - | Set the path to the file containing the options for generation. If other flags are used, they overwrite the options set in the configuration file. If a directory is passed, a config.json file is read from this directory. |
--generateESM | false | Generate ESM compatible code. |
Generate a Client Programmatically
The generator can also be executed programmatically in JavaScript or TypeScript code.
Add the @sap-cloud-sdk/openapi-generator
package to your project:
npm i @sap-cloud-sdk/openapi-generator
This package exports the generate()
function.
It takes the same options as the command-line tool and generates the same files:
import { generate } from '@sap-cloud-sdk/openapi-generator'
const generatorOptions = {
input: 'directoryWithOpenApiFiles';
outputDir: 'myOutputDirectory';
}
await generate(generatorOptions);
How the API Code is Generated
By default, the generator produces one service directory for every OpenAPI specification.
The directory name is based on the file name of the specification and is transformed to kebab case, e.g. my-service
.
APIs
All operations of the service are grouped into APIs based on their tags. A service can consist of multiple APIs. If multiple tags are specified for an operation, only the first one is considered. If no tags are specified, "default" is used.
The API names are transformed by appending "Api" and transforming them to pascal case, e.g. 'my-tag' results in MyTagApi
.
In case the tag already ends with "api" (case independent), one "Api" will be removed, e.g. myapi
results in MyApi
.
If your tags end with "api", but this is part of the word, e.g. "okapi", you can use the OpenAPI vendor extensions and provide an explicit API name ending with "Api", e.g. "OkapiApi".
Note, that operations are grouped into APIs based on their transformed names, not the original names.
Therefore, tags like "my-tag" and "MyTag" are treated as the same API, "MyTagApi".
Operations
Every operation in the specification is reflected as a function of a generated API.
The function names are based on the operationId
property in the specification of the operation.
If no operationId
is given, the name is derived from the method and the path pattern, examples:
'resource'
withPOST
would result increateResource
'resource/{id}'
withGET
would result ingetResourceById
The function names are transformed to camel case, e.g. 'myFunction'. Duplicates within an API are handled by adding an index at the end of the name. In cases where there are duplicate names, but one of the names is in camel case, this name remains as is. Example:
Original operationId s | Generated function names |
---|---|
my-function | myFunction2 |
myFunction | myFunction |
other_function | otherFunction |
Configure Generated Client Structure and Naming
In case you need more flexibility when generating clients, you can use the SAP Cloud SDK's vendor extensions for OpenAPI. The SAP Cloud SDK provides two extensions:
x-sap-cloud-sdk-api-name
to configure the structure and naming of the generated APIs.x-sap-cloud-sdk-operation-name
to configure the generated function names.
You can set those on different levels of the specification. They take precedence before the default behavior.
x-sap-cloud-sdk-api-name
Use this extension to configure the structure of your generated APIs.
Setting x-sap-cloud-sdk-api-name
as a property determines which operations are grouped into one API.
Note, that the name will be transformed to pascal case with an "Api" ending, same as in the default behavior, e.g. "MyApi".
When referring to the "API name", the transformed name is meant.
This extension can be set on the following levels:
- Operations: operations that have the same API name are grouped into one API
- On the path definitions: all operations below paths with the same API name are grouped into one API
- Root of the specification: all operations in the specification belong to the specified API
This extension can be set on all these levels in the same document. In these cases the most specific use of the extension takes precedence.
x-sap-cloud-sdk-operation-name
Use this extension to overwrite the default names for the generated functions.
As of the OpenAPI specification, this is the intent of the operationId
field.
However, the value of this property has to be unique throughout a specification file.
Many OpenAPI validators fail if there are duplicate operationId
s.
With the approach of the SAP Cloud SDK OpenAPI generator this restriction might make the resulting clients more complicated than necessary.
Given that you have multiple APIs, it can make sense to have the same function names in different APIs, e.g. MyResource1Api.getAll()
and MyResource2Api.getAll()
.
The purpose of the x-sap-cloud-sdk-operation-name
is to allow using duplicate names across APIs, while complying with the OpenAPI specification.
npm Packages vs. Local clients
The SAP Cloud SDK OpenAPI client generator generates TypeScript code. By default, it creates only the TypeScript sources.
If you want to use the generated client in your TypeScript code without sharing it, you can work with the default configuration.
If you work with JavaScript, you can enable and configure transpilation with the --transpile
and --tsconfig
flags.
If you want to publish a generated client to an npm registry, in addition to transpiling, you will need a package.json
file for the client.
You can generate it with the --packageJson
flag or include a custom package.json
with the --include
flag.
Make sure to check intellectual property regulations before publishing to a public registry.
The generated clients depend on the @sap-cloud-sdk/openapi
package.
You have to make sure there is a local reference to this package by running:
npm install @sap-cloud-sdk/openapi
Transpilation
If you installed the generator globally and want to transpile the generated code, you have to install the required dependency (or devDependency
) for your client (sap-cloud-sdk/openapi
) prior to generation.
You do this by running:
npm install -D @sap-cloud-sdk/openapi
If you installed the generator as a devDependency
, transpilation will work without additional steps.
Prettier
Since version 2.11.0, the SAP Cloud SDK runs prettier on the generated sources using a default prettier config.
The prettier formats only TypeScript files (.ts
and .d.ts
) to avoid broken source maps.
If you are not happy with the configuration, you can provide a custom configuration using the --prettierConfig
command line argument.
Note that this formatting is done in-memory before the generator emits the files, so no expensive additional I/O is required.
Alternatively, you can execute a custom formatting step after the generation is finished.
Note that custom formatting steps could break source maps when you generate a JavaScript client (option --transpile
enabled).
JavaScript clients should be excluded from formatting because the generated .js
and .map.js
files are not meant for humans to read.