Skip to content

OpenApi Generator #1

@teamon

Description

@teamon

What is this all about?

Generate full tesla-based API client based on Open Api specification file, like this:

defmodule Petstore do
  use Tesla.OpenApi,
    spec: "priv/openapi/petstore.json",
    # (Optional) Dump the generated code for inspection
    dump: "tmp/petstore.exs",
    operations: [
      # (Optional) Generate only selected operations
      only: [
        "findPetById",
        "listPets"
      ]
    ]
end

Petstore.find_pet_by_id(123)
Petstore.list_pets()

Tweet that started it all.

Why?

We already have the great open_api_spex library to generate API spec from Phoenix apps. We should also have an easy way to use this spec from another Elixir app, as an API client.

Why not use existing OpenAPI generators?

Existing generators have quite big dependencies (like docker or java). In case of Elixir, they generate a separate mix package with many files. This is suboptimal, as for every spec change one must regenerate and release a new package.

Here, I propose an alternative, where there are no client API packages at all. The client application can simply depend on tesla and define its own API client module, with customized adapters and middleware. The client is generated on the fly, during regular compilation.

Current To-Do list

  • Figure out how to encode & decode anyOf/oneOf when not backed by models (ad-hoc definitions)
  • Handle "additionalProperties": true
  • Handle formData operation parameters
  • Handle authentication schemes via middlewares
  • Handle optional/required params
  • Cleanup with statements (get rid of {:ok, x} <- {:ok, data["x"]} or {:error, _} <- {:ok, ...} patterns)
  • Generate structs for ad-hoc data models
  • Improve code coverage

Try it today

defp deps do
  [
    {:tesla_oprnapi, github: "elixir-tesla/tesla_openapi"}
  ]
end

# Create your API client in lib/myapi.ex
defmodule MyAPI do
  use Tesla.OpenApi, spec: "myapi_open_api_spec.json"

  def new(token, adapter \\ Tesla.Adapter.Mint) do
    # customize middleware
    middlewares = [
      {Tesla.Middleware.BearerAuth, token: token},
      Tesla.Middleware.Telemetry,
      Tesla.Middleware.Logger
    ]

    super(middlewares, adapter)
  end
end

# See if it works
client = MyAPI.new(token)
MyAPI.some_operation(client)

# For docs, run:
mix docs

Warnings & Notes

This is a very early few-hours-old idea and PoC. We'll see where it goes, if it makes sense, will it be part of tesla or not, etc.

In any case, if you have any ideas or comments, do not hesitate to post them here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions