Reference
Architecture

Architecture

The project is still evolving, but this should give a good overview of the current codebase structure.

Broadly speaking we have the "core" part of the library that should be re-usable across all templates / target languages, and then the template functions.

Some templates also make use of a runtime library.

high level architecture

Core

This directory ./src/core (opens in a new tab) contains the generator/target language agnostic parts of the project.

The process of generation resembles a pipeline.

core architecture

./loaders

Loaders are responsible for fetching a supported input format, and converting it to openapi3 if required, to be handed off to the openapi-validator / openapi-loader.

Two loaders are supported:

  • generic which loads openapi3 specs in JSON/YAML formats
  • typespec which loads typespec specs and converts them in-memory to openapi3

openapi-validator

Nothing particularly interesting here, just takes a loaded document and validates it against the OpenAPI 3 specification in JSON schema format.

Useful for detecting errors due to bad input rather than bugs in the code generation.

Due to a bug (opens in a new tab) in ajv validation is currently skipped for OpenAPI 3.1 documents.

openapi-loader

openapi-loader takes an entry point path, and loads + validates a collection of files ($ref to other files supported).

It then provides typed access to the raw OpenAPI structures, with methods able to convert "maybe refs" into the referenced objects.

This is important because one of the more painful (and bug prone) parts of parsing OpenAPI documents is correctly following $ref's, as you need to carry around the context of which document you came from.

The openapi-loader makes this much less complicated by loading all files up front, and normalizing the contained $refs to absolute paths.

input

Ultimately an instance of the input class is passed to a generator.

The goal of the input class is to provide ergonomic, target language agnostic access to the OpenAPI documents given as input to the generator.

It primarily surfaces API operations, with optional grouping strategies, as a normalized type that has already de-referenced parameters / responses, and set default values on various properties.

Templates

Currently only typescript templates are implemented, living in ./src/typescript (opens in a new tab).

templates architecture

Each template currently has a simple signature: (from ./src/templates.types.ts (opens in a new tab))

export interface OpenapiGeneratorConfig {
  dest: string
  input: Input
  schemaBuilder: SchemaBuilderType
  enableRuntimeResponseValidation: boolean
  compilerOptions: CompilerOptions
  allowUnusedImports: boolean
  groupingStrategy: OperationGroupStrategy
}
 
export interface OpenapiGenerator {
  (args: OpenapiGeneratorConfig): Promise<void>
}

Where dest is a path to a directory to emit code into, and input is an initialized instance of the Input class described above. schemaBuilder refers to zod | joi

You can find all registered generators in ./src/templates.ts (opens in a new tab) - eventually this likely be split into packages that consume the core modules, or some other more pluggable system.