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

SwaggerProvider and byte array #46

Closed
ghost opened this issue Aug 17, 2016 · 6 comments
Closed

SwaggerProvider and byte array #46

ghost opened this issue Aug 17, 2016 · 6 comments

Comments

@ghost
Copy link

ghost commented Aug 17, 2016

Description

The provider does not generate the correct types for format : byte

Repro steps

The following JSON can be used to show the problem, note the testBytes property on the TestDirect type.

{
  "swagger": "2.0",
  "info": {
    "version": "v1",
    "title": "My API"
  },
  "host": "localhost:48213",
  "schemes": [ "http" ],
  "paths": {
    "/api/add": {
      "post": {
        "tags": [ "Tx" ],
        "operationId": "Control_AddApp",
        "consumes": [ "application/json", "text/json", "application/x-www-form-urlencoded", "application/bson" ],
        "produces": [ "application/json", "text/json", "application/xml", "text/xml", "application/bson" ],
        "parameters": [
          {
            "name": "input",
            "in": "body",
            "required": true,
            "schema": { "$ref": "#/definitions/TestDirect" }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "schema": { "type": "boolean" }
          }
        },
        "deprecated": false
      }
    }
  },
  "definitions": {
    "TestDirect": {
      "type": "object",
      "properties": {
        "testBytes": {
          "format": "byte",
          "type": "string"
        }
      }
    }
  }
}

Saving the above JSON to a file, and referencing it like so:

type test = SwaggerProvider< @"C:\Users\user\Desktop\test.json" >
let f e = 
    let a = test.TestDirect()
    a.TestBytes <- e

Hovering over the parameter e shows that the type is string. Additionally, if we view the binary after compilation using ILSpy, we get the following:

...
    // Properties
    .property instance string TestBytes()
    {
        .custom instance void [Newtonsoft.Json]Newtonsoft.Json.JsonPropertyAttribute::.ctor(string) = (
            01 00 09 74 65 73 74 42 79 74 65 73 00 00
        )
        .get instance string test.Client/test/TestDirect::get_TestBytes()
        .set instance void test.Client/test/TestDirect::set_TestBytes(string)
    }

Expected behavior

It is expected that the 'TestBytes' property should allow for byte[].

Known workarounds

Unfortunately there is no workaround apart from not using SwaggerProvider for the API calls that require byte arrays.

Related information

paket.lock:

    SwaggerProvider (0.5.3)
      Newtonsoft.Json (>= 9.0.1)
      YamlDotNet (>= 3.9)
    Swashbuckle.Core (5.4)
      Microsoft.AspNet.WebApi.Core (>= 4.0.20710)
@sergey-tihon
Copy link
Member

sergey-tihon commented Aug 17, 2016

I am not really sure that we should treat string as byte[] in this case ....

You have an another way to specify arrays...

"testBytes": {
    "type": "array",
    "items": {
        "type": "integer"
    }
}

serialization may be tricky if we decide to convert string to byte[]

@sergey-tihon
Copy link
Member

As I understand Swagger spec: format specify structure of type.
In you sample type is string, so swagger provider will receive string from the server, but we have constrain that this string should contain base64 encoded characters.

As workaround you can convert this string manually using

byte[] toBytes = Encoding.ASCII.GetBytes(somestring);
string something = Encoding.ASCII.GetString(toBytes);

@sergey-tihon
Copy link
Member

How did you get this schema? Is it public service? Is it auto-generated from .NET API or hand-written?

@ghost
Copy link
Author

ghost commented Aug 17, 2016

@sergey-tihon sorry for delay responses. Interesting this may be a bug with Swashbuckle rather than SwaggerProvider? I wonder if domaindrivendev/Swashbuckle.WebApi#640 has relevance? I checked my version of Swashbuckle that is used on the WebAPI side and it is '0.5.3' with NewtonSoft '9.0.1'

The schema was generated automatically using F#+WebAPI using a type similar to the following:

namespace API.Models

[<CLIMutable>]
type TestDirect = {
    details  : SomethingElse
    testBytes : byte[]
}

Which was then used on an incoming controller member:

open System.Web.Http
open API.Models
[<RoutePrefix("api")>]
type SomethingControler() =
    inherit ApiController()
    [<Route("test/add")>]
    [<HttpPost>]
    member this.test( [<FromBody>]input: TestDirect) =

The paket.lock for this controller is:

    Microsoft.AspNet.WebApi.Client (5.2.3)
      Newtonsoft.Json (>= 6.0.4)
    Microsoft.AspNet.WebApi.Core (5.2.3)
      Microsoft.AspNet.WebApi.Client (>= 5.2.3)
    Microsoft.AspNet.WebApi.Owin (5.2.3)
      Microsoft.AspNet.WebApi.Core (>= 5.2.3 < 5.3)
      Microsoft.Owin (>= 2.0.2)
      Owin (>= 1.0)
    Microsoft.Owin (3.0.1)
      Owin (>= 1.0)

@ghost
Copy link
Author

ghost commented Aug 17, 2016

Just to note, on #45 (comment), I generated the C# types using the Microsoft REST Client codegen and it produced the correct 'byte[]' type for this situation.

Note2: It ALMOST generated the correct types, it sneakily added this in the SerializeJson function attached to the type:
outputObject["testBytes"] = Convert.ToBase64String(this.TestBytes);

It seems that Swashbuckle stuff is not treating these things in a nice way, how do people send data (you cant base64 200MB easily!).

Note3: this is interesting domaindrivendev/Swashbuckle.WebApi@03e028c shows that System.Byte[] is parsed to new Schema { type = "string", format = "byte" };

@sergey-tihon
Copy link
Member

Should be fixed in v0.5.4

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

No branches or pull requests

1 participant