aj-foster / open-api-generator

Open API code generator for Elixir
MIT License
97 stars 13 forks source link

Parsing arrays when parameter is of type array, style simple, explode false #59

Open sharonlinto opened 1 month ago

sharonlinto commented 1 month ago

Hi AJ, thank you for making this codegen for Elixir! I was running into a problem and was wondering if you could help/provide advice?

In my project OpenAPI spec, I am using a GET parameter specified like this:

get:
   parameters:
      ...
      - name: listOfIds
         in: path
         required: true
         schema:
            type: array
            items:
               type: string
               format: uuid
            minItems: 1
         explode: false
         style: simple

When I code generate, the typespec of the module says that the type listOfIds is of [String.t()] which is correct, however the generated module is like the following:

@spec module([String.t()], keyword) ::
          {:ok, SomeOutput.t()} | {:error, SomeError.t()}
  def module(listOfIds, opts \\ []) do
    client = opts[:client] || @default_client
    query = Keyword.take(opts, [:pageSize, :pageToken])

    client.request(%{
      args: [listOfIds: listOfIds],
      call: {Clients.CoreApi.MyCall, :module},
      url: "/listOfIds/#{listOfIds}",
      method: :get,
      query: query,
      response: [
        {200, {Clients.CoreApi.SomeOutput, :t}},
        {401, :null},
        {404, :null}
      ],
      opts: opts
    })
  end

If listOfIds = [AAAA, BBBB, CCCC, DDDD], I expect that url should parse to /listOfIds/AAAA,BBBB,CCCC,DDDD according to the OpenAPI Spec. However, what I actually get is /listOfIds/AAAABBBBCCCCDDDD (no comma seperation).

My current work around is to pre-join (Enum.join(listOfIds, ",")) my listOfIds before passing it into the module, but was wondering if there is way for the codegen to join array parameters, given that the typespec is aware that listOfIds is an array

aj-foster commented 1 month ago

Today I learned: so much. Thank you for sharing this.

The Parameter Serialization page you linked, and its 3.1.0 counterpart, show a few different variations of path parameter encoding I wasn't aware of. In the short term, you're doing the best thing: users of the generated function should pre-join the list of IDs. In the long term, the generator should have all of the information necessary to make better choices for these parameters.

I'll get to work on that. In the meantime, do you have an example specification that uses this type of path parameter? I'd love to add it to the list of examples I use to check for regressions.

aj-foster commented 1 month ago

Started some exploration in #62.

sharonlinto commented 1 month ago

@aj-foster sorry for the delayed response! is the following what you mean for an example spec?

openapi: 3.0.2
info:
  title: Test api
  version: "0.1"
servers:
  - url: /v1
paths:
  /projects/{projectID}/something/{somethingID}/blahs:
    get:
      description: Returns the list of blahs for something.
      operationId: listBlahsForSomething
      parameters:
        - name: project
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/project"
        - name: somethingID
          in: path
          required: true
          schema:
            type: array
            items:
              $ref: "#/components/schemas/somethingID"
            minItems: 1
          explode: false
          style: simple
components:
  schemas:
    projectID:
      type: string
      format: uuid
    somethingID:
      type: string
      format: uuid