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

[HASKELL] haskell-http-client generator doesn't understand allOf schemas #7411

Open
thomasjm opened this issue Jan 15, 2018 · 10 comments
Open

Comments

@thomasjm
Copy link

Description

I'm trying to generate haskell-http-client code to use with Docker's API. However, the codegen seems to be not understanding what to do when an allOf is found in a schema. For example, Docker's v1.25 API contains this snippet:

paths:
  ...
  /containers/create:
    post:
      summary: "Create a container"
      ...
      parameters:
        ...
        - name: "body"
          in: "body"
          description: "Container to create"
          schema:
            allOf:
              - $ref: "#/definitions/Config"
              - type: "object"
                properties:
                  HostConfig:
                    $ref: "#/definitions/HostConfig"
                  NetworkingConfig:
                    description: "This container's networking configuration."
                    type: "object"
                    properties:
                      EndpointsConfig:
                        description: "A mapping of network name to endpoint configuration for that network."
                        type: "object"
                        additionalProperties:
                          $ref: "#/definitions/EndpointSettings"
...

However, in the generated code for this API endpoint, the "body" type is simply missing:

-- | @POST \/containers\/create@
-- 
-- Create a container
-- 
containerCreate 
  :: (Consumes ContainerCreate contentType, MimeRender contentType )
  => ContentType contentType -- ^ request content-type ('MimeType')
  -> Accept accept -- ^ request accept ('MimeType')
  ->  -- ^ "body" -  Container to create
  -> DockerEngineRequest ContainerCreate contentType InlineResponse201 accept
containerCreate _  _ body =
  _mkRequest "POST" ["/containers/create"]
    `setBodyParam` body
Swagger-codegen version

Version 2.3.1

Swagger declaration file content or url

See above for snippet; URL is https://docs.docker.com/engine/api/v1.25/swagger.yaml

Command line used for generation

rm -rf /tmp/haskell_api_client; mkdir /tmp/haskell_api_client; java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate -i https://docs.docker.com/engine/api/v1.25/swagger.yaml -l haskell-http-client -o /tmp/haskell_api_client

Steps to reproduce

Clone the swagger-codegen repo and then run the command above inside it. You can see the problematic code in /tmp/haskell_api_client/lib/DockerEngine/API.hs

Related issues/PRs

Not that I can see.

Suggest a fix/enhancement

I'm guessing the codegen is simply missing handling for this case. It might be necessary to generate a whole new type for the "combined" body created by an allOf. It might also be possible to do something clever with a product type of the components of the allOf and then handle packing/unpacking them in the Aeson ToJSON/FromJSON instances.

@jonschoning
Copy link
Contributor

I will review - thanks

@jonschoning
Copy link
Contributor

jonschoning commented Jan 16, 2018

This appears to be an issue with all generators (at least those using static types), as far as I can tell.

I tried generating with

  • csharp-dotnet2
  • java
  • rust
  • scala
  • swift
  • swift3

and they all fail for this case.

related issues:

#2924
#4146
#3225
#6318
#6639
#6983
#7477

moby/moby#27919
moby/moby/pull/35132
moby/moby#35146

Since this appears to be an issue with the base/core swagger-codegen code, I'm not sure there's an immediate fix i can make to haskell-http-client to get it working.

I recommend modifying the swagger.yaml directly to inline/remove the allOf directives, get it working in the interim.

Some issues mention moving the allOf into a model definition, but I'm not sure if that will work either.

Would like to hear from others on if this is an expected use case. @wing328

@thomasjm
Copy link
Author

Ah okay, thanks for investigating @jonschoning!

Slightly off-topic, but another workaround I tried was to use selective generation to exclude problematic parts, i.e. something like java -Dmodels=User,Pet -DmodelTests=false {opts} (as described on the main swagger-codegen README). However, this seemed to generate no code output at all, no matter what options I tried. Is selective generation supposed to work with haskell-http-client?

@jonschoning
Copy link
Contributor

Selective generation does appear to be a bug with haskell-http-client (I've never actually tested it before, as I wasn't quite sure what the use case was.) I still recommend editing the yaml file directly if at all possible.

@thomasjm
Copy link
Author

The other use-case for selective generation besides working around bugs is that some APIs are gigantic--when I compile the whole Docker API it results in a ~20MB Haskell library. Is it possible it will be added someday? I'm happy to open an issue for it if it helps.

@jonschoning
Copy link
Contributor

jonschoning commented Jan 17, 2018

for haskell-http-client you should always combine -Dmodels with -DsupportingFiles . Then it will avoid generating the APIs.

To control the specific files being generated, -Dmodels=User (a single model) seems to work, but any models User depends on won't be available.

I wasn't able to get the CSV list of -Dmodels=User,Pet or -Dmodels="User,Pet" to work with the java generator.

@eeishaan
Copy link

You can add go-server generator to the list as well.

swagger: '2.0'
info:
  version: 0.0.1
  description: so many issues
  title: superb api
host: 'localhost:8080'
basePath: /
schemes:
  - http

definitions:
  stuff-group:
    properties:
      stuffs:
        properties:
          stuff:
            items:
              allOf:
                - $ref: '#/definitions/stuff-group2'
                - properties:
                    stuff-name:
                      type: string
                      description: Name of the stuff
            x-key: stuff-name
            type: array
  stuff-group2:
    properties:
      foo:
        type: string
        description: superb value

When fed into the generator, I get the following error:

[main] ERROR io.swagger.codegen.DefaultCodegen - String to be sanitized is null. Default to ERROR_UNKNOWN
[main] ERROR io.swagger.codegen.DefaultCodegen - unexpected missing property for name Stuff
[main] WARN io.swagger.codegen.DefaultCodegen - skipping invalid array property {
  "baseName" : "stuff",
  "getter" : "getStuff",
  "setter" : "setStuff",
  "datatype" : "[]ErrorUnknown",
  "datatypeWithEnum" : "[]ErrorUnknown",
  "name" : "Stuff",
  "defaultValue" : "null",
  "defaultValueWithParam" : " = data.stuff;",
  "baseType" : "array",
  "containerType" : "array",
  "jsonSchema" : "{\n  \"type\" : \"array\",\n  \"x-key\" : \"stuff-name\"\n}",
  "exclusiveMinimum" : false,
  "exclusiveMaximum" : false,
  "hasMore" : false,
  "required" : false,
  "secondaryParam" : false,
  "hasMoreNonReadOnly" : false,
  "isPrimitiveType" : false,
  "isContainer" : true,
  "isNotContainer" : false,
  "isString" : false,
  "isNumeric" : false,
  "isInteger" : false,
  "isLong" : false,
  "isNumber" : false,
  "isFloat" : false,
  "isDouble" : false,
  "isByteArray" : false,
  "isBinary" : false,
  "isFile" : false,
  "isBoolean" : false,
  "isDate" : false,
  "isDateTime" : false,
  "isUuid" : false,
  "isListContainer" : true,
  "isMapContainer" : false,
  "isEnum" : false,
  "isReadOnly" : false,
  "vendorExtensions" : {
    "x-key" : "stuff-name"
  },
  "hasValidation" : false,
  "isInherited" : false,
  "nameInCamelCase" : "Stuff",
  "isXmlAttribute" : false,
  "isXmlWrapped" : false
}

The generated stub looks like this:

package swagger

type xxx struct {

	Stuff []ErrorUnknown `json:"stuff,omitempty"`
}

@huan
Copy link

huan commented Aug 3, 2018

I ran into this issue today, get a String to be sanitized is null. Default to ERROR_UNKNOWN error too.

Had you fixed your problem, do you have any solution for it?

@cjlyth
Copy link

cjlyth commented Sep 7, 2018

Same error with latest version os master using the Java CLI and maven plugin.

@ivanbakel
Copy link

This seems to be resolved for Haskell at least, using 2.4.21.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants