swagger-api / swagger-codegen

swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.
http://swagger.io
Apache License 2.0
16.96k stars 6.04k forks source link

[Scala] Error Uploading File as Multipart Form #5855

Open kristenstarr opened 7 years ago

kristenstarr commented 7 years ago
Description

For one of our endpoints that requires file upload, we are seeing errors with the multipart content type.

Model of Endpoint:

"post": {
        "description": "Uploads a file.",
        "consumes": ["multipart/form-data"],
        "parameters": [{
          "name": "file",
          "in": "formData",
          "description": "Uploaded file",
          "type": "file",
          "required": true
        }],
        "summary": "File Upload",
        "responses": {
              ...
        }
      }

Stack Trace:

Cannot get entity on a MultiPart instance (through reference chain: com.sun.jersey.multipart.FormDataMultiPart["entity"])
com.fasterxml.jackson.databind.JsonMappingException: Cannot get entity on a MultiPart instance (through reference chain: com.sun.jersey.multipart.FormDataMultiPart["entity"])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388)
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:348)
    at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:343)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:698)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:292)
    at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3681)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3057)
    at io.swagger.client.ApiInvoker.serialize(ApiInvoker.scala:107)
    at io.swagger.client.ApiInvoker.invokeApi(ApiInvoker.scala:145)

The line in ApiInvoker which is causing the error is contained in the serialize method below

 def serialize(obj: AnyRef): String = {
    if (obj != null) {
      obj match {
        case e: List[_] => mapper.writeValueAsString(obj.asInstanceOf[List[_]].asJava)
        case _ => mapper.writeValueAsString(obj)  // <-- ERROR occurs here
      }
    } else null
  }
Swagger-codegen version

We have tested on the most recent release of 2.2, as well as building our own jar from the master branch at commit 802641bf919225cad6c924f681942576982d3d3a (May 21). Also, have checked out the 2.3 branch to see if this is fixed, but find the Scala client to be very reorganized and things like auth header functionality to be missing.

Swagger declaration file content or url
"post": {
        "description": "Uploads a file.",
        "consumes": ["multipart/form-data"],
        "parameters": [{
          "name": "file",
          "in": "formData",
          "description": "Uploaded file",
          "type": "file",
          "required": true
        }],
        "summary": "File Upload",
        "responses": {
              ...
        }
      }
Command line used for generation

Not command line, but rather an SBT build time dependency on the jar.

SwaggerCodegen.main("generate -l io.swagger.codegen.languages.ScalaClientCodegen -i apidocs.json"
Steps to reproduce
  1. Generate a scala api client from a declaration file containing an endpoint specifying parameters type:file, in:formData, and consumes:['multipart/form-data'] as above.

  2. Write a test of the generated code that attempts to upload a File object. api.method(file)

  3. Observe that the request does not even get made, serialization of the body fails in the ApiInvoker.

wing328 commented 7 years ago

Also, have checked out the 2.3 branch to see if this is fixed, but find the Scala client to be very reorganized and things like auth header functionality to be missing.

Thanks for testing the 2.3.0 branch as well, which has the Scala generator rewritten. The goal is to combine scala, async-scala and akka-scala into one single Scala generator. It's still work in progress. cc @clasnake

As a workaround, what about using the Java SDK in your Scala application?

kristenstarr commented 7 years ago

Thanks for the response! For now, that is exactly what we are doing. We are building both the scala and the java clients- because we find the pattern matching features of scala very helpful in the cleanliness and organization of our tests but require this one feature that is not working. My goal is to be able to simplify down to just the one (scala) as soon as this is working.

wing328 commented 7 years ago

@kristenstarr right, this feature definitely needs to be fix (despite the workaround) and I would suggest fixing it in the 2.3.0 branch instead. If you've time to help with the fix, I can probably show you some good starting points.

kristenstarr commented 7 years ago

sure, will give it a shot. I'm much more familiar with whats on master and 2.2, having debugged through it quite deeply, but will get into 2.3.0 and try to understand the direction that it's going.