Posting JSON body in Smart Object

  • 2 September 2022
  • 20 replies
  • 449 views

Hi, using REST API integration, I have a method that is suppose to post a JSON body.

I have used fiddler to intercept the request received from the endpoint.

 

This is what I need to post (This is working in postman):

[
{
"mediaId": "ZAA4398F9",
"color": "RED",
"duration": 60,
"pattern": "FLASH_4_TIMES"
}
]

 

So in my smart object, I pass the body as a serialised item:
{"$type":"CY_Imagotag.k2RESTidentifier_MediasFlash, CY_Imagotag, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","mediaId":"ZAA4398F9","color":"RED","duration":60,"pattern":"FLASH_4_TIMES"} ​
I have sniffed the request using fiddler, other parameters are receiving it correctly. But not the JSON body portion. The server is receiving a blank body.
 

 

 

 

20 replies

Userlevel 3
Badge +9

Your postman body seems to be an array.


 


Try calling the Serialize Add Item To Array method on the relevant SmartObject so that you have an array of your items rather than a singular one.


 


The take the output of the Serialized Array property and try passing that along.


 


Cheers.

Hi Paul, 


I have tried that, but it won't even reach the server


Getting this error message.


Inner: Object of type 'Newtonsoft.Json.Linq.JArray' cannot be converted to type 'REST_UNITED.k2RESTidentifier_MediasFlashArray'.


 
Userlevel 3
Badge +9

From looking at the message it seems as though you are trying to serialize with the wrong SmartObject so that the types that it gets annotated with are not the ones that your subsequent REST call is expecting. 


 


You may have a SmartObject called MediasFlashArray - you would need to use the Serialize Add Item To Array on that one rather than the one you are using currently then take that output and pass it along.


 


If you look at the example I have attached you can see that the two values I pass in are added to an array of the type ChatMessageBody:


 



 


This may help to explain as well:  https://help.nintex.com/en-US/k2blackpearl/userguide/current/default.htm#ServiceBrokers/EndPoints/SmartObject_Serialization-Deserialization.htm?TocPath=Administer%257CK2%2520Workspace%257CManagement%2520Console%257CSmartObject%2520Services%257CUnderstanding%2520SmartObject%2520Service%2520Types%252FService%2520Brokers%257CGeneric%252FEndPoints%2520Service%2520Types%257C_____6


 


Cheers

Hi Paul,


I have tried all different methods of serialising but it is not working yet 😞 These are the output of the different type of serialised methods.


 


1.Serialize
Input:
{"$type":"REST_UNITED.k2RESTidentifier_MediasFlash, REST_UNITED, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","color":"RED","duration":42,"mediaId":"A12345","pattern":"some_patterns"}
Result:
This reaches the server, but I get a error 400. Upon checking the endpoint log, the above is not posting any json in the body.



2. Serialize Add Item to Array
Input:
{"$type":"REST_UNITED.k2RESTidentifier_MediasFlash[], REST_UNITED, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","$values":[{"$type":"REST_UNITED.k2RESTidentifier_MediasFlash, REST_UNITED, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","color":"RED","duration":60,"mediaId":"A1234567","pattern":"FLASH_4_TIMES"}]}
Result:
Object of type 'Newtonsoft.Json.Linq.JArray' cannot be converted to type 'REST_UNITED.k2RESTidentifier_MediasFlashArray'.


 


3. Serialize Item To Array
Input:
{"$type":"REST_UNITED.k2RESTidentifier_MediasFlash[], REST_UNITED, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","$values":[{"$type":"REST_UNITED.k2RESTidentifier_MediasFlash, REST_UNITED, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","color":"RED","duration":60,"mediaId":"A1234567","pattern":"FLASH_4_TIMES"}]}
Result:
Object of type 'Newtonsoft.Json.Linq.JArray' cannot be converted to type 'REST_UNITED.k2RESTidentifier_MediasFlashArray'.


 


4. Serialize List to Array
I'm not sure what to input as "Serialize List", so not able to test this. Any idea what do I need to pass this?



Is there anything I'm missing out? 


Thank you very much in advanced. 


 

Userlevel 3
Badge +9

Hi,


 


It looks like you are attempting the correct things but without seeing your actual endpoint it is difficult to debug. Are you able to post your swagger file here as well as the names of the methods that you are trying to call and some example values for the other properties that you are passing back?


 


Cheers


 


 

Hi Paul, 


 


The JSON Descriptor file is here.












Userlevel 3
Badge +9

Hi there,


 


How did you create your SmartObjects?  Did you do it using the SmartObject tester at all, or did you do it manually?  If it is using the tester then you may be falling foul of this:  - "Each path can define only one of each operation type. For example, a path cannot define two get operations. If you are describing a service that exposes two GET calls for the same path try appending an extraneous query parameter to make Swagger see it as a different path"


 


I generated the SmartObjects from your given endpoint and I see that there was no Service Operation Id for the method 5d7130879808460f78f0074c so what I did was as per:


 

I modified the line 3362 to "/domains/{domain}/medias/flash?workaround=bob": {

 

Then when I generated the SmartObjects on the service instance I did get a SmartObject under the Service Operations that matched the operation id so try the above and regenerate them and try calling that one instead.

 

The newly generate method seems to only take a singular flashingParameter object (the json you added was in an array so I though that was the case).

 

I then called the Serialize method on the FlashingParameter SmartObject and passed that to the flashingParameter SmartObject on the _5d7130879808460f78f0074c_ method.

 


If however you created it manually (it may also apply if you did it manually as the service instance would still have only generated the first method it came across, I didn't test this) then hopefully the above screenshot should help with the values that you need to post across.


 


Cheers


Hi Paul,


 


When creating the REST Broker service, I ticked the box to create the SmartObject automatically.


 


The method I am using is at [REST Broker Name] -> Object Types ->  Media -> Methods -> _5d39b285d10b8b087c47df48_


 


Method to Serialise -> Object Types -> MediasFlash


In this folder there will be serialised/serialised to array etc...


 


The method that you're using "5d7130879808460f78f0074c" just tested this, it is working with the "FlashingParameter". However this method I found it under "Service Operations" folder, instead of the "Object Folder"


 


Does it mean I can only call a REST method if they are inside the "Service Operations Folder"?
Since the method that I want only have it in the "Object Folder" but not in the "Service Operations Folder".


 


If so this will be weird as well.


In my Postman I have around 40+ methods when I import the same JSON file.


but in K2, I'm only getting 12 methods under Service Operations.


So being new in this REST broker service, I thought it will be normal if it falls under the object folder


 

Userlevel 3
Badge +9
That is just the way K2 has generated your SmartObjects based on the given JSON file.

You have a number of options to make it clearer.

You can move the SmartObject somewhere more sensible for you environment.

You can rename the operation Id if you have control over the swagger file to something more easily identifiable the regenerate the SmartObjects.

And the thing that I would always prefer to do is after registering the Service Instance I create my own SmartObjects on top of service instance as it allows me to create them with identifiers that fit better for both the name and methods.

RE: the 40 versus 12 thing this is because of the path collision stuff as mentioned above. You can add a dummy query string property to the end of certain paths to get them to be exposed on the Service Instance.

Cheers

Hi Paul,


 


1. Imported the descriptor in RESTUnited


2. Only leave the flashmedia method then I export it.


3. However, still unable to post anything that is an array.


 


The flashmedias only descriptor file is here.


https://github.com/chinyongcy/Collins-Imagotag/blob/main/imagotag-flashmediaonly.json

Userlevel 3
Badge +9

Hi


 


Try changing Model0 to this, it looks like it doesn't currently conform to the K2 standard:


 



    "Model0": {

      "properties": {

      "type": "array",

      "items": {

        "$ref": "#/definitions/Array"

      }

    }

 

 

Cheers

Hi Paul, 


 


Just tried with a new services


Using Model 0 (Serialised Item to Array):


I get this


{"$type":"swagger_fixed.k2RESTidentifier_Array[], swagger_fixed, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","$values":[{"$type":"swagger_fixed.k2RESTidentifier_Array, swagger_fixed, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null","mediaId":"AA439C66","color":"BLUE","duration":120,"pattern":"FLASH_4_TIMES"}]}


 


Execute Model 1 (Post Media Flash)


Passing the above into the body, I get back this error message


Error Message: Broker execution failed. (Inner: Object of type 'Newtonsoft.Json.Linq.JArray' cannot be converted to type 'swagger_fixed.k2RESTidentifier_Model0'.)

Userlevel 3
Badge +9

Hi again,


 


The method you are posting to doesn't require an Array (there are no [] at the end of the name).


 


So you can get away with just calling the Serialize method on the Model0 object that I've included in the .txt file below.


 


You only need to pass arrays across when the input requires multiples of the same thing.


 


See screenshot:


 



 


Cheers

Hi Paul,


 


The method requires me to pass it as an array.


 


So in postman, even though i pass one item, i need to pass it with the square bracket.



but if I don't pass it with the square bracket.



 


 


So thought that I will need to serialise to array even though if it is one item.


 


In K2, I have tried using the serialised method, it will return me a error 400, same as the postman error as I didn't post it as an array.



 


In fiddler itself, now at least i am seeing some content getting posted. Just need the serialised to array to work.



 

Userlevel 3
Badge +9

Sorry then - I'm kind of out of ideas at this point.


 


I've looked through all the REST endpoints that I've configured and can't find any where it takes an array of objects at the top level.


 


Do you have control over the API itself?  If so can you create a new method that only accepts a single object as its input?


 


Cheers

Hi Paul,


 


Thank you so much for the help so far. It made me understand how k2 and swagger works a lot better. So went to do some more research on swagger. To save you time from the long post, you can scroll down for the workaround!


 


Tried to some swagger file and visualise the output, So for attached "sample_swagger.json.txt", it works great when I placed it in https://editor.swagger.io/ (at least when the visualisation comes out)



 


Then I checked against my descriptor file. (Attached custom_descriptor.json.txt)



 


It looks great (made no edit to it, other than the operationid on the JSON file as well as the dummy query)


 


After I renamed the operation id ,everything become clearer. The usual way of passing the parameters without K2 giving me any error message of converting..


1. Serialise MediaFlash (Object -> MediaFlash -> Serialise)


2. Pass the above output into FlashMedias  (Object -> Medias -> FlashMedias)


3.  Sniffed using Fiddler, check the request body is still {}


Expected it to be 


[ {


"some key": "some values"


...


...


}]


 


So did a bit of study of the swagger file


FlashMedias (POST Method) depends on MediasFlashArray (Object/Model) 


MediasFlashArray depends on MediaFlash


So when I serialised using "MediaFlash" -> Since the method requires a MediasFlashArray Model. 


So here comes the problem.... I feel it's a K2 bug. Anything that requires an Array on the top level it just won't work on K2, despite the evidence on the above screenshot.


 


So what I have tried next,  instead of FlashMedias depending on MediasFlashArray. I change the schema to MediasFlash. Just trying my luck, I tried to pass a serialised Array of MediasFlash. This didn't work, will give me the error on cannot convert etc...


 


Since thinking that the parameter type is always "application/JSON", and switching from "text" to "JSON" works in postman. I had an idea to pass the parameter as string.


1. I've created a new schema call JSON with a type string.


2. Duplicated the POST methods I needed. Name it to e.g. FlashMediaJSON


3. Replace anything that requires an array schema to the JSON schema.


 



 


With this at least I can build a custom string in the smart form and pass it to the smart object.


Not the most elegant way of doing things, but it's the best that I can come to a compromise without doing anything to the endpoints. 


 


Thank you so much Paul! Couldn't have "solved" it without you explaining the basics of Swagger and how K2 "deals" with Swagger..

Userlevel 3
Badge +9

Hi,


No worries, it took me a while and a lot of experimenting to get it right in my mind.


 


Now that you've a working solution you may not want to make any further changes but you are able to add default HTTP Headers that will be sent with every request.  This might address your issue and allow you to use things properly.


 


If you go to the category where any of your generated SmartObjects live for a REST service you'll see under the System Types Category a SmartObject called HttpHeader - on that you can use our old friend Serialize Add Item To Array setting all desired headers.  This can then be added to the Service Instance config on the Default HTTP Headers value:


 



This will then always pass that on all your calls.  Alternatively you can change the Add HTTP Request Header Property to Methods which will give you a HttpHeader input on each SmO call that you can then fill with Arrays of Headers as well.


 


Cheers

Hi Paul,


Still won't really deem it as e solution, but spent too much time on this integration already. Will use this solution while trying to look off the way to do it properly. Will update here to share with the community if I find any. 


 


But don't really get the part where editing the headers to "make things work properly". Mind troubling you to explain more on this part 😂 Or is it actually more dependent on the endpoint?


 
Userlevel 3
Badge +9

You mentioned that in your PostMan request you set a bunch of headers on the request to get it to post correctly.


 


You can mimic the same behaviour on your REST calls by adding those headers to the Service Instance configuration property as per my post above so you have parity between your PostMan and K2 REST calls to your endpoint.


 


By doing this, it may change the request in such a way that your endpoint accepts the request successfully without you having to do the workaround you are currently using.


 


Cheers

Badge

Hi Paul,

 

 

 

 

Thank you so much for the help so far. It made me understand how k2 and swagger works a lot better. So went to do some more research on swagger. To save you time from the long post, you can scroll down for the workaround!

 

 

 

 

 

Tried to some swagger file and visualise the output, So for attached "sample_swagger.json.txt", it works great when I placed it in https://editor.swagger.io/ (at least when the visualisation comes out)

 

 

26020iDEE4E4C0C4EB920B.png

 

 

 

 

 

Then I checked against my descriptor file. (Attached custom_descriptor.json.txt)

 

 

26022iBBFBBE46A26BE2AC.png

 

 

 

 

 

It looks great (made no edit to it, other than the operationid on the JSON file as well as the dummy query)

 

 

 

 

 

After I renamed the operation id ,everything become clearer. The usual way of passing the parameters without K2 giving me any error message of converting..

 

 

1. Serialise MediaFlash (Object -> MediaFlash -> Serialise)

 

 

2. Pass the above output into FlashMedias  (Object -> Medias -> FlashMedias)

 

 

3.  Sniffed using Fiddler, check the request body is still {}

 

 

Expected it to be 

 

 

[ {

 

 

"some key": "some values"

 

 

...

 

 

...

 

 

}]

 

 

 

 

 

So did a bit of study of the swagger file

 

 

FlashMedias (POST Method) depends on MediasFlashArray (Object/Model) 

 

 

MediasFlashArray depends on MediaFlash

 

 

So when I serialised using "MediaFlash" -> Since the method requires a MediasFlashArray Model. 

 

 

So here comes the problem.... I feel it's a K2 bug. Anything that requires an Array on the top level it just won't work on K2, despite the evidence on the above screenshot.

 

 

 

 

 

So what I have tried next,  instead of FlashMedias depending on MediasFlashArray. I change the schema to MediasFlash. Just trying my luck, I tried to pass a serialised Array of MediasFlash. This didn't work, will give me the error on cannot convert etc...

 

 

 

 

 

Since thinking that the parameter type is always "application/JSON", and switching from "text" to "JSON" works in postman. I had an idea to pass the parameter as string.

 

 

1. I've created a new schema call JSON with a type string.

 

 

2. Duplicated the POST methods I needed. Name it to e.g. FlashMediaJSON

 

 

3. Replace anything that requires an array schema to the JSON schema.

 

 

 

 

 

26023i89E3E44A44F382D3.png

 

 

 

 

 

With this at least I can build a custom string in the smart form and pass it to the smart object.

 

 

Not the most elegant way of doing things, but it's the best that I can come to a compromise without doing anything to the endpoints. 

 

 

 

 

 

Thank you so much Paul! Couldn't have "solved" it without you explaining the basics of Swagger and how K2 "deals" with Swagger..

 

Hi chinyongcy,

 

I'm currently facing the same issue with a REST API. 
I'm trying to follow your steps, but I couldn't figure out how to 'recreate' the POST methods to replace the array with a JSON schema.

Could you please explain how you handled the following steps, and perhaps provide an example for FlashMediaJSON:

1. I've created a new schema call JSON with a type string.

2. Duplicated the POST methods I needed. Name it to e.g. FlashMediaJSON

3. Replace anything that requires an array schema to the JSON schema.

 

Regards,

Reply