Skip to main content

Tools

Existen innumerables herramientas para auxiliar OpenAPI.

Podemos buscar algunas en:

El Swaggerhub ofrece toda una suite para esto con generadores de código y todo lo demás, después haz un overview allí y ve si funciona para ti. Independiente de todo, siempre es bueno conocer las cosas.

Vamos a hablar sobre el OpenAPI Generator que a pesar de ese nombre incluye varios recursos además de la generación de código. El repositorio del OpenAPI Generator en Github puede ser útil también para ayudar.

La ventaja del uso de herramientas como esta es la cantidad de patrocinadores que tiene. Yendo directo a la documentación oficial tenemos varias maneras de usar.

Ya con la herramienta instalada en el terminal tenemos lo siguiente:

❯ openapi-generator --version
openapi-generator-cli 7.10.0
commit : 12dfe8f
built : -999999999-01-01T00:00:00+18:00
source : https://github.com/openapitools/openapi-generator
docs : https://openapi-generator.tech/

❯ openapi-generator
usage: openapi-generator-cli <command> [<args>]

The most commonly used openapi-generator-cli commands are:
author Utilities for authoring generators or customizing templates.
batch Generate code in batch via external configs.
config-help Config help for chosen lang
generate Generate code with the specified generator.
help Display help information about openapi-generator
list Lists the available generators
meta MetaGenerator. Generator for creating a new template set and configuration for Codegen. The output will be based on the language you specify, and includes default templates to include.
validate Validate specification
version Show version information used in tooling

See 'openapi-generator-cli help <command>' for more information on a specific
command.

Para quien no quiera instalar la herramienta puede usar docker. El comando openapi-generator es el entrypoint del container. Haz un alias en tu shell, es una propuesta interesante también.

docker run --rm \
-v ${PWD}:/local openapitools/openapi-generator-cli
usage: openapi-generator-cli <command> [<args>]

The most commonly used openapi-generator-cli commands are:
author Utilities for authoring generators or customizing templates.
batch Generate code in batch via external configs.
config-help Config help for chosen lang
generate Generate code with the specified generator.
help Display help information about openapi-generator
list Lists the available generators
meta MetaGenerator. Generator for creating a new template set and configuration for Codegen. The output will be based on the language you specify, and includes default templates to include.
validate Validate specification
version Show version information used in tooling

See 'openapi-generator-cli help <command>' for more information on a specific
command.

Ya usamos para validar la api que hicimos, pero vamos a utilizar nuevamente para recordar

# Todo correcto
❯ openapi-generator validate -i infoapi.yaml
Validating spec (infoapi.yaml)
No validation issues detected.

Forzando un error para probar.

security:
# - BasicAuth: []
# - JwtAuthToken: []

Voy a hacer usando docker para entender el proceso.

docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli validate -i /local/infoapi.yaml
Validating spec (/local/infoapi.yaml)
Errors:
- attribute security is not of type `array`

[error] Spec has 1 errors.

Podemos generar el código a partir de esta api. La lista está disponible aquí y podemos ver por la cli.

openapi-generator list
The following generators are available:

CLIENT generators:
- ada
- android
- apex
- bash
- c
- clojure
- cpp-qt-client
- cpp-restsdk
- cpp-tiny (beta)
- cpp-tizen
- cpp-ue4 (beta)
- crystal (beta)
- csharp
- dart
- dart-dio
- eiffel
- elixir
- elm
- erlang-client
- erlang-proper
- gdscript
- go
- groovy
- haskell-http-client
- java
- java-helidon-client (beta)
- java-micronaut-client (beta)
- javascript
- javascript-closure-angular (beta)
- javascript-flowtyped
- jaxrs-cxf-client
- jetbrains-http-client (experimental)
- jmeter
- julia-client (beta)
- k6 (beta)
- kotlin
- lua (beta)
- n4js (beta)
- nim (beta)
- objc
- ocaml
- perl
- php
- php-dt (beta)
- php-nextgen (beta)
- powershell (beta)
- python
- python-pydantic-v1
- r
- ruby
- rust
- scala-akka
- scala-gatling
- scala-http4s
- scala-pekko
- scala-sttp
- scala-sttp4 (beta)
- scalaz
- swift-combine
- swift5
- swift6 (beta)
- typescript (experimental)
- typescript-angular
- typescript-aurelia
- typescript-axios
- typescript-fetch
- typescript-inversify
- typescript-jquery
- typescript-nestjs (experimental)
- typescript-node
- typescript-redux-query
- typescript-rxjs
- xojo-client
- zapier (beta)


SERVER generators:
- ada-server
- aspnet-fastendpoints
- aspnetcore
- cpp-pistache-server
- cpp-qt-qhttpengine-server
- cpp-restbed-server
- cpp-restbed-server-deprecated
- csharp-functions
- erlang-server
- fsharp-functions (beta)
- fsharp-giraffe-server (beta)
- go-echo-server (beta)
- go-gin-server
- go-server
- graphql-nodejs-express-server
- haskell
- haskell-yesod (beta)
- java-camel
- java-helidon-server (beta)
- java-inflector
- java-micronaut-server (beta)
- java-microprofile
- java-msf4j
- java-pkmst
- java-play-framework
- java-undertow-server
- java-vertx-web (beta)
- java-wiremock (beta)
- jaxrs-cxf
- jaxrs-cxf-cdi
- jaxrs-cxf-extended
- jaxrs-jersey
- jaxrs-resteasy
- jaxrs-resteasy-eap
- jaxrs-spec
- julia-server (beta)
- kotlin-server
- kotlin-spring
- kotlin-vertx (beta)
- kotlin-wiremock (beta)
- nodejs-express-server (beta)
- php-flight (experimental)
- php-laravel
- php-lumen
- php-mezzio-ph
- php-slim4
- php-symfony
- python-aiohttp
- python-blueplanet
- python-fastapi (beta)
- python-flask
- ruby-on-rails
- ruby-sinatra
- rust-axum (beta)
- rust-server
- scala-akka-http-server (beta)
- scala-cask
- scala-finch
- scala-http4s-server
- scala-lagom-server
- scala-play-server
- scalatra
- spring


DOCUMENTATION generators:
- asciidoc
- cwiki
- dynamic-html
- html
- html2
- markdown (beta)
- openapi
- openapi-yaml
- plantuml (beta)


SCHEMA generators:
- avro-schema (beta)
- graphql-schema
- ktorm-schema (beta)
- mysql-schema
- postman-collection (beta)
- protobuf-schema (beta)
- wsdl-schema (beta)


CONFIG generators:
- apache2

Ahora vamos a generar código a partir de la especificación de la API que tenemos. Cada lenguaje que queremos generar código nos ofrece diferentes tipos de personalizaciones. Las configuraciones para generación de código en go también pueden ser vistas por la CLI.

❯ openapi-generator config-help -g go

CONFIG OPTIONS

disallowAdditionalPropertiesIfNotPresent
If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default. (Default: true)
false - The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.
true - Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.

enumClassPrefix
Prefix enum with class name (Default: false)

generateInterfaces
Generate interfaces for api classes (Default: false)

generateMarshalJSON
Generate MarshalJSON method (Default: true)

generateUnmarshalJSON
Generate UnmarshalJSON method (Default: true)

hideGenerationTimestamp
Hides the generation timestamp when files are generated. (Default: true)

isGoSubmodule
whether the generated Go module is a submodule (Default: false)

packageName
Go package name (convention: lowercase). (Default: openapi)

packageVersion
Go package version. (Default: 1.0.0)

prependFormOrBodyParameters # Vamos a usar esto aquí en el ejemplo ya.
Add form or body parameters to the beginning of the parameter list. (Default: false)

structPrefix
whether to prefix struct with the class name. e.g. DeletePetOpts => PetApiDeletePetOpts (Default: false)

useDefaultValuesForRequiredVars
Use default values for required variables when available (Default: false)

useOneOfDiscriminatorLookup
Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and only one match in oneOf's schemas) will be skipped. (Default: false)

withAWSV4Signature
whether to include AWS v4 signature support (Default: false)

withGoMod
Generate go.mod and go.sum (Default: true)

withXml
whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML) (Default: false)

Un comando que es bueno conocer y a pesar de no estar en la CLI es el completion que nos ayuda a usar mejor la CLI.

# ¿Qué podemos hacer a partir del validate?
❯ openapi-generator completion validate
--recommend
-i
--input-spec

❯ openapi-generator validate -i infoapi.yaml --recommend
Validating spec (infoapi.yaml)
Warnings:
- While technically allowed, GET/HEAD with request body may indicate programming error, and
is considered an anti-pattern.

[info] Spec has 1 recommendation(s).

##### ---------

❯ openapi-generator completion list
-s
--short
-i
--include
-d
--docsite
--github-nested-index


❯ openapi-generator list -s
ada,ada-server,android,apache2,apex,asciidoc,aspnet-fastendpoints,aspnetcore,avro-schema,bash,crystal,c,clojure,cwiki,cpp-qt-client,cpp-qt-qhttpengine-server,cpp-pistache-server,cpp-restbed-server,cpp-restbed-server-deprecated,cpp-restsdk,cpp-tiny,cpp-tizen,cpp-ue4,csharp,csharp-functions,dart,dart-dio,eiffel,elixir,elm,erlang-client,erlang-proper,erlang-server,fsharp-functions,fsharp-giraffe-server,gdscript,go,go-echo-server,go-server,go-gin-server,graphql-schema,graphql-nodejs-express-server,groovy,kotlin,kotlin-server,kotlin-spring,kotlin-vertx,kotlin-wiremock,ktorm-schema,haskell-http-client,haskell,haskell-yesod,java,jaxrs-cxf-client,java-helidon-client,java-helidon-server,java-inflector,java-micronaut-client,java-micronaut-server,java-msf4j,java-pkmst,java-play-framework,java-undertow-server,java-vertx-web,java-camel,jaxrs-cxf,jaxrs-cxf-extended,jaxrs-cxf-cdi,jaxrs-jersey,jaxrs-resteasy,jaxrs-resteasy-eap,jaxrs-spec,javascript,javascript-flowtyped,javascript-closure-angular,java-wiremock,jetbrains-http-client,jmeter,julia-client,julia-server,k6,lua,markdown,java-microprofile,mysql-schema,n4js,nim,nodejs-express-server,objc,ocaml,openapi,openapi-yaml,plantuml,perl,php,php-flight,php-nextgen,php-laravel,php-lumen,php-slim4,php-symfony,php-mezzio-ph,php-dt,postman-collection,powershell,protobuf-schema,python,python-pydantic-v1,python-fastapi,python-flask,python-aiohttp,python-blueplanet,r,ruby,ruby-on-rails,ruby-sinatra,rust-axum,rust,rust-server,scalatra,scala-akka,scala-cask,scala-pekko,scala-akka-http-server,scala-finch,scala-gatling,scala-http4s,scala-http4s-server,scala-lagom-server,scala-play-server,scala-sttp,scala-sttp4,scalaz,spring,dynamic-html,html,html2,swift5,swift6,swift-combine,typescript,typescript-angular,typescript-aurelia,typescript-axios,typescript-fetch,typescript-inversify,typescript-jquery,typescript-nestjs,typescript-node,typescript-redux-query,typescript-rxjs,wsdl-schema,xojo-client,zapier

Debes haber observado que tenemos generación tanto del lado del cliente como del lado del servidor. Obviamente que el código generado para el lado del cliente es diferente del código generado del lado del servidor.

Vamos a conocer un poco mejor este comando pero podemos consultar la documentación del generate también.

# Observarás que muestra tanto los comandos short como por extenso.
❯ openapi-generator completion generate
-e
--engine
-a
--auth
--global-property
--library
-v
--verbose
--schema-mappings
--enable-post-process-file
--skip-validate-spec
--inline-schema-options
--server-variables
--artifact-id
--api-name-suffix
--operation-id-name-mappings
-c
--config
--release-note
-g # Vamos a usar
--generator-name
--generate-alias-as-model
-s
--skip-overwrite
--name-mappings
--enum-name-mappings
--log-to-stderr
--git-repo-id
--legacy-discriminator-behavior
--instantiation-types
--invoker-package
--model-package
--ignore-file-override
-o
--output
--model-name-suffix
--parameter-name-mappings
--api-package
--model-name-mappings
--git-host
--strict-spec
--type-mappings
--git-user-id
--merged-spec-filename
--openapi-generator-ignore-list
--openapi-normalizer
-p
--additional-properties
--minimal-update
--remove-operation-id-prefix
--dry-run
--language-specific-primitives
--skip-operation-example
--http-user-agent
-t
--template-dir
--model-name-prefix
--inline-schema-name-mappings
--reserved-words-mappings
--import-mappings
--artifact-version
--group-id
--input-spec-root-directory
--package-name
-i
--input-spec

Por ejemplo, vimos que tenemos en go la opción de configuración prependFormOrBodyParameters que marqué allá arriba. Para cambiar esa opción podemos setear directamente en el comando.

# --dry-run es solo una simulación para no ejecutar y ve si el comando funciona y cuál sería nuestra salida
openapi-generator-cli generate -g go --additional-properties=prependFormOrBodyParameters=true -o ./out -i infoapi.yaml --dry-run
# Para pasar varias opciones --additional-properties=key1=value1,key2=value2

Pero no puedes estar haciendo esto. Crea un archivo generatorconfig-go.yaml con la configuración de los parámetros y vamos a apuntarlo.

prependFormOrBodyParameters: true
# key2: value2
# key3: value3
❯ openapi-generator generate -i infoapi.yaml -g go -c generatorconfig-go.yaml  -o ./goproject --dry-run

Todavía puedes mover todos los argumentos que hicimos arriba a un archivo yaml o json usando el batch. No voy a documentar aquí pero es bueno conocer.

Dependiendo del generador elegido vamos a generar el código del lado del cliente o del lado del servidor.

Generando código en go del lado del servidor necesitamos usar el generator go-server.

❯ openapi-generator generate -i infoapi.yaml -g go-server  -o ./go-server
[main] INFO o.o.codegen.DefaultGenerator - Generating with dryRun=false
[main] INFO o.o.c.ignore.CodegenIgnoreProcessor - Output directory (/Users/davidprata/Desktop/gitlab/devsecops/docs/development/openapi//docs/development/openapi/resources/./go-server) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.
[main] INFO o.o.codegen.DefaultGenerator - OpenAPI Generator: go-server (server)
### ... REMOVIDO PARA FACILITAR LA LECTURA

Ahora generando del lado del client vamos a usar el generator go.

❯ openapi-generator generate -i infoapi.yaml -g go  -o ./go-client
[main] INFO o.o.codegen.DefaultGenerator - Generating with dryRun=false
[main] INFO o.o.c.ignore.CodegenIgnoreProcessor - Output directory (/Users/davidprata/Desktop/gitlab/devsecops/docs/development/openapi//docs/development/openapi/resources/./go-client) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.
[main] INFO o.o.codegen.DefaultGenerator - OpenAPI Generator: go (client)
[main] INFO o.o.codegen.DefaultGenerator - Generator 'go' is considered stable.
### ... REMOVIDO PARA FACILITAR LA LECTURA
# Archivos diferentes para proyectos diferentes
ls go-client
README.md docs model_beer_order.go model_paged_response_pageable.go
api git_push.sh model_beer_order_line.go model_paged_response_pageable_sort.go
api_beer.go go.mod model_beer_paged_list.go response.go
api_customer.go go.sum model_brewery.go test
api_order_service.go model__v1_customers__customer_id__orders_post_request.go model_customer.go utils.go
client.go model_address.go model_customer_paged_list.go
configuration.go model_beer.go model_paged_response.go

ls go-server
Dockerfile README.md api go go.mod main.go