E-xyza / Apical

OpenAPI Compiler for Elixir
MIT License
65 stars 6 forks source link

Option to generate routes across multiple controllers #41

Closed gmile closed 1 year ago

gmile commented 1 year ago

Question

Asking since this wasn't immediately clear from the documentation, but how does one use the single .json/.yaml schema to generate routes to actions across multiple controllers?

Based on the current example from the docs, it looks like the app would have to have a single controller only?

Apical.router_from_file(
  "path/to/openapi.yaml",
  controller: MyProjectWeb.ApiController
)

Or alternatively, split the OpenAPI schema file into multiple files, then invoke Apical.router_from_file/2 multiple times referring to different file and each time a different controller.

Instead, would it not be more convenient to have an option to generate routes for many controllers/actions from the schema - for example, to improve code organisation: one could have a single .json/.yaml schema, and multiple controller files. I believe having multiple controller files is somewhat a de-facto standard approach of code organisation, for example, in projects using Phoenix framework.

For example, imaging OpenAPI Schema describes two families of routes: posts and comments:

GET /posts
POST /posts
PUT /posts/:id
GET /posts/:id
DELETE /posts/:id
GET /posts/:post_id/comments
POST /posts/:post_id/comments
PUT /comments/:id
GET /comments/:id
DELETE /comments/:id

It would be nice to have Apical generate routes to actions from two controllers:

GET /posts                    -> PostController#index
POST /posts                   -> PostController#create
PUT /posts/:id                -> PostController#update
GET /posts/:id                -> PostController#show
DELETE /posts/:id             -> PostController#destroy
GET /posts/:post_id/comments  -> CommentController#index
POST /posts/:post_id/comments -> CommentController#craete
PUT /comments/:id             -> CommentController#update
GET /comments/:id             -> CommentController#show
DELETE /comments/:id          -> CommentController#destroy

Proposed solution

I think one way to achieve this could be for Apical to derive the names of controller and action from based on some conventional information of the operation.

For example, it could be convenient to use operationId to store the a value of PostController#index string. Then, Apical would use this string to build a route to the said controller:

openapi: 3.1.0
  info:
    title: My API
    version: 1.0.0
  paths:
    "/posts":
      post:
        operationId: "PostController#create"
        responses:
          "200":
            description: OK
# ...

One problem with this approach could be that, at the compilation time, all controller modules must already exist.

ityonemo commented 1 year ago

You can set controllers on a per-operation basis or by tag!

ityonemo commented 1 year ago

https://github.com/E-xyza/Apical/blob/main/test/controllers/by_operation_id_test.exs

https://github.com/E-xyza/Apical/blob/main/test/controllers/by_tag_test.exs

ityonemo commented 1 year ago

I apologize for this not being documented well but I punted writing guides to 0.2+ to get this out faster.

ityonemo commented 1 year ago

Note that naming in the operationId is not a good idea since client platforms will typically build their function calls off of the operationId string so we want to be nice to our clients

ityonemo commented 1 year ago

However, based on your suggestions, I'm adding:

https://github.com/E-xyza/Apical/issues/42