Skip to content

OpenAPI spec based generation

jchuahtacc edited this page Mar 30, 2021 · 12 revisions

Open API Generators

This project demonstrates a pattern for automatic type and request generation of TypeScript types and API calls for the PetStore swagger spec. A few observations:

  • The project automatically generates a package in gen/api, which is then imported into the main source code
  • The generated source creates async/await based functions that run a request with parameters and headers specified by the OpenAPI spec
  • The generated source is then included as a module in the main react-redux-saga based application, which has access to strong types tied to API utility functions, but must still implement saga code by the old fashioned way

First glance takeaways:

  • We could leverage this pattern (which uses @openapitools/openapi-generator-cli) to generate the base types and API calls for TAPIS and spin it off as a separate lower level repository tapis-api that can be consumed by any framework
  • The generated api calls could then be wrapped by tapis-redux middleware, replacing the generic tapisFetch utility function with calls to the external automatically generated tapis-api package
  • The generator, while useful for generating the types, does not automatically buy us well defined hooks and components. It simply resolves the type and API call generation on our behalf.

openapi-generator-cli Experimental Results:

I made a working branch task/tui-19--openapi. This branch adds an npm command called "api". You can autogenerate from spec by doing the following:

  • Make sure you have a Java runtime installed
  • Install the openapi-generator-cli with npm install -g @openapitools/openapi-generator-cli (need to figure out how to properly configure this project for npx so that you don't have to install these commands to your global node_modules)
  • Run the api generator with npm run api

This will autogenerate the Tenants API spec and place it in tapis-api. Here is what I found

  • openapi-generator-cli, despite being a node package, requires a java virtual machine to be installed
  • We may require a single OpenAPI spec for all the services, otherwise we will end up generating multiple API packages per individual service
  • Upon trying to consume the TAPIS OpenAPI spec, it generates the many errors similar to this:
src/apis/index.ts:4:1 - error TS2308: Module './LdapsApi' has already exported a member named 'CreateLdapRequest'. Consider explicitly re-exporting to resolve the ambiguity.

4 export * from './TenantsApi';
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The generator cannot continue after this point. This may be caused by duplicate names. The LDAP specification contains CreateLdapRequest, and this is repeated in the Tenants specification.

Using this tool would either require manual curation of generated artifacts or changing the existing OpenAPI specs to resolve name conflicts. However, this is the official tool and is well supported with two years of development by 10 contributors.

Artifacts from this generator are available here.

openapi-generator-plus Tool

This is a different tool available as an npm cli tool openapi-generator-plus. This tool is plugin based and does not require Java. Documentation is sparse. This generator uses a different package generation strategy which avoids the naming export conflict. Additionally it generates types.

Artifacts from this generator are available here.

This tool works out of the box. This unofficial tool is a single developer project with a year of maturity. It could be dangerous to rely on this tool if it were to become unmaintained.

URL and Authorization

Both tools provide a way of specifying a "configuration" object that allows setting the base URL and any required auth headers.

Making a tapis-api project

It may be more feasible to spin off a separate tapis-typescript-api project and publish it as an npm package that is consumed downstream by tapis-ui, etc. This project could collate all of the various service specs and publish by version.

OpenAPI spec idiosyncracies

It appears that the OpenAPI spec for tenants often provides two slightly different types for POST objects. For example, Tenant as a result and NewTenant as a post body object. Both CLIs generated separate objects for each. If the OpenAPI spec is cleaned up to use inheritance, this may result in fewer automatically generated types and a better end user experience for the generated TypeScript types. A cursory glance at multiple TAPIS v3 services shows inconsistencies in naming between different services. For example, in the Tenants API objects schemas may be Tenant and NewTenant but in the Systems API it may be TSystem and ReqCreateSystem.

Before generating a public tool, it would be good to revise existing specifications for consistency as well as compatibility with the official openapi-generator-cli tool.