Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenApi Generator #1

Open
2 of 8 tasks
teamon opened this issue Aug 30, 2021 · 7 comments
Open
2 of 8 tasks

OpenApi Generator #1

teamon opened this issue Aug 30, 2021 · 7 comments

Comments

@teamon
Copy link
Member

teamon commented Aug 30, 2021

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.

@maennchen
Copy link

@teamon I was trying to achieve something similar (it is by no means finished). Maybe you'll find some inspiration?

https://github.com/jshmrtn/openapi-compiler

@kernel-io
Copy link

this looks like a wonderful feature, I have been using openapi-generator before and encountered the same issues you have raised. watching with interest :)

@julien-leclercq
Copy link

julien-leclercq commented Oct 21, 2021

Hey ! As a user of the openapi generator I must say that I really like your idea.
Do you plan to generate documentation along with the generated module functions ?
I'll try to make a few experiment in the next days, if they are interesting what would be a good place to share them?

@teamon teamon pinned this issue Dec 17, 2021
@yordis
Copy link
Member

yordis commented Feb 26, 2022

@teamon how are you thinking to deal with $ref and remote $ref in schemas and multiple files to define the spec?

@teamon teamon unpinned this issue May 8, 2022
@teamon teamon self-assigned this May 8, 2022
@teamon teamon transferred this issue from elixir-tesla/tesla May 8, 2022
@teamon teamon removed their assignment May 8, 2022
@yordis
Copy link
Member

yordis commented Oct 25, 2024

I want to get this situation done, but I feel that we should strategically use https://github.com/OpenAPITools/openapi-generator from Java, even though it makes me quite unhappy.

Primarily because many SaaS companies have already leveraged the tool to provide the SDK for other languages.

I keep overthinking this one.

@teamon
Copy link
Member Author

teamon commented Oct 25, 2024

I've tried to build an OpenAPI generator at least three times now and I've always failed.

The main reasons usually being:

  • It's hard to cover all OpenAPI spec details
  • Some OpenAPI specs are generated in a way that basically prevents any reasonable generation
  • The generated code will always be just a bit off from one would write by hand
  • For the vast majority of cases I ended up using just few API methods instead of the whole thing
  • Generating and compiling a lot of code that won't be used is just waste (of time & energy)
  • Tesla is great for builing tiny clients for just the things I needed

I also got used to not having SDK for anything in Elixir so I got used to the default of just building it myself in 10 LOC. And if there is an Elixir SDK there's always something that I don't like about it 😅

Maybe it's just that tesla's high-level API is good for humans to write API clients and when you need to generate one you might as well use some lower-level lib like mint or finch.

@yordis
Copy link
Member

yordis commented Oct 25, 2024

@teamon same here! I am onboard. I am primarily interested in strategically put the Elixir logo or name out there.

Aside from this, I am writing a series of Explanations about anti-patterns as well. Maybe I should implement elixir-tesla/tesla#531 since, the intent is to have a replicable copy+paste way to build these functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: In Progress
Development

No branches or pull requests

5 participants