Open-generator-cli problems, or Swagger/OpenApi recommendations

Yes, that is the solution to my problem. I will run it each time I run open-generator.

Sorry for late response. Iā€™m glad you like my ideas. Would you like me to re-base and open a PR with what I have so far? Or would you rather start from scratch?

Very good idea. Even generation of requests will be easier that way.

No problem. I already started working on a major refactoring. Iā€™ve changed so much a PR wouldnā€™t make much sense.

First release

As the matter of fact I planned on publishing a first version here on discourse today. It does not yet support allOf and recursive types, but it would be great to have some first feedback. The current changes include:

  • Drop support for Elm 0.18;
  • Drop Main.elm;
  • Put all models in a single file;
  • Nest generated code in a module called Api, i.e. Api.Data for models and Api.Request.* for operations;
  • Introduce the Request type for improved customization of requests (operations).

You can download the jar here. Use it by running

java -jar openapi-generator-cli.jar generate -i /your/openapi.yaml -g elm -o /path/to/write/to

# smoke test the output
cd /path/to/write/to
elm make src/**/*.elm

When you run into an issue and would like to report it, please provide a minimal fully working yaml/json file so I can easily reproduce the issue.

Any comments/suggestions/errors are welcome!

1 Like

Thank you! I tested it on my project. There are a generic object in the api, a class called ProblemDetails that belongs to Asp.Net Core 3.0, so I need to delete the following from the swagger.json

     ,
      "extensions": {
        "type": "object",
        "nullable": true,
        "additionalProperties": {}
      }

Once I removed that and generate, it will create the non-ok recursive definition:

 type alias FormElement =
     { name : String
     :
     , elements : Maybe (List FormElement)
     }

After removing the field elements in the elm code and in the encoder+decoder, the Elm compiler complains about more things. I use Elm 0.19.

You can find the swagger.json file at https://send.firefox.com/download/bcfa78a4c3bbf523/#Fq54jecJJPXS2jp6x1KyWA

Thanks for your report @mattiasw.

  • I think it would only make sense to map the additionalProperties: {} to a Dict String () as it can be of any type. However, this makes it quite useless;
  • Recursion is still on its way;
  • The other issues I have fixed.

Please try this updated jar. Thanks.

@eriktimmers Thank you for your hard work. Yes, you are correct. All problems are solved.

Regarding the extensions field for ProblemDetails, I think it should not even be there. There is a specification for it: https://tools.ietf.org/html/rfc7807 and I actually think that NSwag and/or Aspnet handles it incorrectly. I think the intention is that all key-value pairs in extensions should be lifted to top level in ProblemDetails.

Improvement suggestion: NSwag also includes the names for enums, and they could be used for creating union types. In my case, the names are String, Number and Bool. The union names should probably be something like EValueType_String, EValueType_Number , EValueType_Bool. Here is a similar request: https://github.com/swagger-api/swagger-ui/issues/5272

  "EValueType": {
    "type": "integer",
    "description": "",
    "x-enumNames": [
      "String",
      "Number",
      "Bool"
    ],
    "enum": [
      0,
      1,
      2
    ]
  },

Let me know when you fixed the recursion too, and I will remove all remnants of the old generated code.

Thanks, @mattiasw. I wanted to refactor anyway so I have a good test case now.

I am not sure about the x-enumNames yet. They donā€™t seem part of the official spec and Iā€™m not sure I want to support custom extensions at this point. Why is the enum not generated using the names in the first place?

I am almost done with the allOf support. After that Iā€™ll start working on the recursion. My PR for that has just been merged into the generator.

The x-enumNames feature seems only to be used by nswag currently, so I understand low prio.

Most likely, it is only needed for C#, which represents enums as numbers internally. It is only really useful in the intersection C# on the server, and a client language with enums or union types. So, it wouldnā€™t surprise me if the only openapi generator that supports it is the one for typescript, https://www.typescriptlang.org/docs/handbook/enums.html

Keep us posted. To make it easier to find by other elm:ers, it is also listed at https://korban.net/elm/catalog/ but maybe you can add some elm specific information somewhere.

Even if C# uses numbers internally the (de)serialization could handle strings, right? But OK, I do not know the details for that.

Hereā€™s a new release including support for allOf. Using allOf adds all properties to another type. If the original type also has a discriminator(1) the original type is added using composition and (2) a custom type is creating with all the possible sub-types and a fallback base type (see my edited comment above).

The indentation of the generated files stopped working, so you generate something like this:

type alias BOAttachment =
    { filename : String
, url : String
}

Used to work fine.

Thatā€™s weird. ā€œWorks on my machineā€. Can you try on another device?

Hereā€™s a new one with support for recursive types! Please give it a try!

I still have the indentation problem. I am using the swagger.json file I linked to previously. After adding elm-format, it compiles fine. Remove it, and Data.elm fails.

The recursive structure seems ok and compiles, however, I have not tested it yet in my code.

This is the Windows cmd file I run

java -jar openapi-generator-cli-4.jar generate -g elm -i swagger.json -o src/Swagger/
cd src/Swagger/
call elm-format --yes ./src/
call elm make src/Api.elm src/Api/Data.elm src/Api/Request/Acc.elm src/Api/Request/Account.elm src/Api/Request/Attachment.elm src/Api/Request/Cmd.elm src/Api/Request/CmdAdmin.elm src/Api/Request/CmdGuest.elm src/Api/Request/Frm.elm src/Api/Request/Grid.elm src/Api/Request/Home.elm src/Api/Request/Ins.elm src/Api/Request/InsPdf.elm src/Api/Request/InsView.elm src/Api/Request/LoggedOut.elm src/Api/Request/NoAccount.elm src/Api/Request/SignIn.elm src/Api/Request/UserContext.elm src/Api/Request/Usr.elm src/Api/Request/Version.elm
cd ..
cd ..

Iā€™ll see if I can reproduce it on another machine.

Forgot to export the recursion type. Try this one instead.

Another update!

  • Add missing catch-all type for allOfs;
  • Drop support for post-processing of files;
  • Only import UUID/Time when actually used.

Applied the code generated with openapi-generator-cli-6.jar to the whole project. Two bugs detected, first one in this entry.

The type is enum over ints, however the code assumes the server sends values as string:

  "EValueType": {
    "type": "integer",
    "description": "",
    "x-enumNames": [
      "String",
      "Number",
      "Bool"
    ],
    "enum": [
      0,
      1,
      2
    ]
  },

I had to patch the generated code like this:

eValueTypeDecoder : Json.Decode.Decoder EValueType
eValueTypeDecoder =
    Json.Decode.string
        |> Json.Decode.andThen
            (\str ->
                case str of
                    "0" ->
                        Json.Decode.succeed EValueType0

                    "1" ->
                        Json.Decode.succeed EValueType1

                    "2" ->
                        Json.Decode.succeed EValueType2

                    other ->
                        Json.Decode.fail <| "Unknown type: " ++ other
            )

to

eValueTypeDecoder : Json.Decode.Decoder EValueType
eValueTypeDecoder =
    Json.Decode.int
        |> Json.Decode.andThen
            (\str ->
                case str of
                    0 ->
                        Json.Decode.succeed EValueType0

                    1 ->
                        Json.Decode.succeed EValueType1

                    2 ->
                        Json.Decode.succeed EValueType2

                    other ->
                        Json.Decode.fail <| "Unknown type: " -- ++ other
            )

Also, I expected the Error case to pop up just like during network problem, but instead I had to debug the javascript to find out why it failed.

The urls contains a double // in url, for example http://localhost:5000//Acc/current/forms

Fixed by removing the initial / in the path on all files in Request directory.

cmdGet : String -> Api.Request Api.Data.Form
cmdGet cmdName =
    Api.request
        "GET"
        "/Cmd/{cmdName}"
        [ ( "cmdName", identity cmdName ) ]
        []
        []
        Nothing
        Api.Data.formDecoder

to

cmdGet : String -> Api.Request Api.Data.Form
cmdGet cmdName =
    Api.request
        "GET"
        "Cmd/{cmdName}"
        [ ( "cmdName", identity cmdName ) ]
        []
        []
        Nothing

The indentation problem is still there, but I run elm-format every time, so not important.

Also, any special reason you have the parameters for Api.send in that order? If you swap them, same order as v1 Http.send, all I have to do is replace my Http.send to Api.send in the rest of the project.

@mattiasw thanks for the feedback!

Good point. Iā€™ll make it work with integers as well.

Can you elaborate on this? I donā€™t understand what you mean.

I think you should fix the base path in your OpenAPI JSON. It should not end with / if you want to get rid of the //. The path in the request itself is correct.

I still would like to have this fixed. Were you able to run this on a second machine? I still havenā€™t been able to reproduce this.

Nope I did that by accident. Already fixed it in my unreleased code.

Iā€™ve also started working on a Gitbook for some background, guidance and technical details on the OpenAPI Generator and Elm. Would be great if you could have a look when itā€™s ready.

Thanks @eriktimmers for the quick response!

Look at the screenshot above, that is how I found that Elm expected a string, and got an int. I expected it would have been by an Err-msg, i.e. that my client would have presented it as any Http-ajax-error message, for example a network timeout.

In the swagger.json file, there is no /, it says:

  "servers": [
    {
      "url": "http://localhost:5000"
    }
  ],