Forum Discussion

evosus's avatar
evosus
Occasional Contributor
9 years ago
Solved

Interactive API Docs / POST body data omitted using consumes 'application/x-www-form-urlencoded'

Steps to duplicate:

 

Take for example this api which defines a method capable of consuming application/x-www-form-urlencoded and text/plain:

https://swaggerhub.com/api/evosus/webapi/1.3.0

POST /method/Inventory_Item_StockSiteQuantity_Get

 

Enter the 3 required fields as follows:

CompanySN: 20091102165026*177

ticket: d5fef8e5-a3d3-456e-b4a9-5203c947ee97

body: blah blah blah

 

With parameter content-type set to application/x-www-form-urlencoded and click 'Try this out'. Notice the -d parameter in the curl command is missing.

curl -X POST --header "Content-Type: application/x-www-form-urlencoded" --header "Accept: application/json" "https://cloud3.evosus.com/api/method/Inventory_Item_StockSiteQuantity_Get?ticket=d5fef8e5-a3d3-456e-b4a9-5203c947ee97&CompanySN=20091102165026*177"

 

With parameter content-type set to text/plain click 'Try this out'. Notice the -d parameter is set properly.

curl -X POST --header "Content-Type: text/plain" --header "Accept: application/json" -d "blah blah blah" "https://cloud3.evosus.com/api/method/Inventory_Item_StockSiteQuantity_Get?ticket=d5fef8e5-a3d3-456e-b4a9-5203c947ee97&CompanySN=20091102165026*177"

 

Is there something I am doing wrong? Thanks in advance for your assistance. 

 

  • evosus's avatar
    evosus
    9 years ago

    I got to the bottom of the problem. I can't argue with your observation that I don't have CORS enabled since it was throwing the CORS error. Specifically an error during the preflight request. Preflight is the key word.

     

    A pre-flight request is only associated with a complex CORS request and not a simple CORS request. My request WAS simple when my content-type was x-www-form-urlencoded. When I changed my request to content-type application/json the CORS requirement, by definition, changed to COMPLEX. This is explained in the excellent HTMLRocks CORS topic (http://www.html5rocks.com/en/tutorials/cors/).

     

    I had the CORS headers, as shown above on my POST request. However, the preflight request uses the OPTIONS verb. My web service did not handle the OPTIONS verb. Now it does. Now it works.

     

    Most web service implementations will probably find it easiest to implement the handling of OPTIONS calls using a request filter. Check for the OPTIONS verb and short-circuit the request with a null response prior to route handling. Alternately you can implement an OPTIONS verb in the route handler in addition to your other http verbs. The calling web site only needs to see the proper headers in the response.

      

    Thanks for your support.

6 Replies

  • Hi there,

     

    The problem lies within the Swagger spec you have. Body parameters can't really be used with application/x-www-form-urlencoded and vice versa. If you need to use application/x-www-form-urlencoded, then you have to define the parameter(s) as formData (but then you will not be able to specify models). If you do you want to have a body payload for an operation, then the mime type would represent the data type to be sent. For example, if you expect to get a JSON, the mime type would be application/json.

    • evosus's avatar
      evosus
      Occasional Contributor

      +1 for getting model working for formData.

       

      What I am trying to express is one or the other of these HTTP requests (these work directly in Fiddler):

       

      GET http://cloud3.evosus.com/api/method/Inventory_Item_StockSiteQuantity_Get?args={"ItemCode":"23154BIO"}&ticket=d5fef8e5-a3d3-456e-b4a9-5203c947ee97&CompanySN=20091102165026*177 HTTP/1.1

      Accept: application/json
      Host: cloud3.evosus.com

      -----

       

      POST http://cloud3.evosus.com/api/method/Inventory_Item_StockSiteQuantity_Get?ticket=d5fef8e5-a3d3-456e-b4a9-5203c947ee97&CompanySN=20091102165026*177 HTTP/1.1

      Accept: application/json
      Content-Type: application/x-www-form-urlencoded
      Host: cloud3.evosus.com

       

      args={"ItemCode":"23154BIO"}

      -----

       

      You can see that I am expressing the model as JSON in the value of the args parameter. In the case of the POST, the body is application/x-www-form-urlencoded. I can express a model of any type using this technique.

       

      I am finding it very difficult to express what is needed for my server API. I already know that the Interactive API Docs UI will not produce the needed request without some manual editing of the parameters. However, had the use of a body parameter allowed Content-Type: application/x-www-form-urlencoded to be used I could have instructed the user to click the Model Schema to populate the template of the body and then prepend the body with 'args='. But this is not possible.

       

      My current workaround is to create an 'args' query parameter of type string, and an optional body parameter referencing my model. I accompany this with instructions to click the Model Schema box and cut the contents of the body into the args query parameter. Very hacky but it works. It would be slightly better if instead of an 'args' query parameter I could use a formData parameter. But I cannot have a body and a formData parameter together. The UI is blocking me at every turn. 

       

      Can I do better some other way?

      • RonRatovsky's avatar
        RonRatovsky
        Moderator

        This is my personal opinion - we're not going to support that kind of structure, not for query parameters and not for form parameters (of that structure). The only way to pass a model is if you define how it's being represented and when it comes to HTTP, the way to do is is to define the mime type of the content which affects the *payload* only. To me, it just doesn't make sense.

         

        If you have only one parameter, I don't really understand why you don't define it as application/json and just send it as a payload (the "args" name doesn't add anything).

         

        However, putting all that aside, there's really no way to describe what you want with 2.0. This is not a SwaggerHub issue but rather a spec restriction that cannot change within SwaggerHub.