Send JSON Via HTTP request

Caché

Hi Guys,

 

Basically I'm looking for a sample what I can send data in aJSON format to a a webservice using an http request pls?

I've found some documentation on %Net.HttpRequest but a sample on how to connect to a Webservice and send data to it would be really helpful?

Our clients are running Cache & Ensemble 2014 

 

Thanks

  • 0
  • 0
  • 3268
  • 20
  • 1

Answers

Here's a sample request with JSON payload from %ZEN.proxyObject, with object->json serialization via %ZEN.Auxiliary.jsonProvider:

Set Body = ##class(%ZEN.proxyObject).%New()
Set Body.Prop1 = "Val1"
Set Body.Prop2 = "Val2"
Set Array = ##class(%ListOfDataTypes).%New()
Do Array.Insert(1)
Do Array.Insert(2)
Do Array.Insert(4)
Set Body.Array = Array
Set Request= ##class(%Net.HttpRequest).%New()
Set Request.Server = "server"
Set Request.Location = "location"
Set Status = ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(Request.EntityBody,  Body)
Set Status = Request.Post()

Payload looks like this:

Do Body.%ToJSON()
{
        "Array":[1,2,4
        ],
        "Prop1":"Val1",
        "Prop2":"Val2"
}

Documentation on %Net. HttpRequest.

Where does Array go to proxyObject ?
I'm missing something like: Set Body.Array=Array

Thank you, Robert. Missed that during copy&paste from terminal. Fixed.

Thank you very much Eduard that answered my question.

but what I'm puzzled about is that in my Ensemble 2014  can't find properties Prop1, Prop2...etc in %ZEN.proxyObject documentation, and also when for example Typing dot(.) after Body in my code Prop1 or Prop2 is not in the list !? and the same happens with  CopyFrom in %Net.HttpRequest, you can find Write method but not the Copyfrom method so how do we suppose to know those properties and methods? and what the Maximum Props we can have ?

set hr=##class(%Net.HttpRequest).%New()
 d hr.EntityBody.Write("Data into stream")
 do hr.EntityBody.CopyFrom(file)

 Thanks Eduard

 

 

 can't find properties Prop1, Prop2...etc in %ZEN.proxyObject documentation

They are dynamic (defined via %DispatchGetProperty/%DispatchSetProperty) so you can assign any properties to %ZEN.proxyObject.

 CopyFrom in %Net.HttpRequest, you can find Write method but not the Copyfrom method so how do we suppose to know those properties and methods?

Unable to reproduce (on 2017.2 though).

You may try to use #Dim directive:

#Dim Stream As %GlobalBinaryStream
Set Stream = ##class(%GlobalBinaryStream).%New()
Do Stream.Write("111")
Set Request.EntityBody = Stream

Autocomplete works better for variables defined with #Dim (also it's useful for lists/arrays with objects).

what the Maximum Props we can have ?

1000 properties per class.

 

They are dynamic (defined via %DispatchGetProperty/%DispatchSetProperty) so you can assign any properties to %ZEN.proxyObject.

That's news to me, never heard about such functionality and that's really cool and handy! does that applies only for %ZEN.proxyObject, any %ZEN objects or any other objects !?

 

thanks

 

You can redefine these dynamic dispatch methods:

  • %DispatchGetProperty / %DispatchSetProperty / %DispatchSetMultidimProperty
  • %DispatchGetModified / %DispatchSetModified
  • %DispatchMethod / %DispatchClassMethod

And they are available for all classes.

Hi Eduard,

I thought that would the end of it but ...:)

I've created the below sample to post a JSON object but the receiving Web Service didn't receive anything ! Am I missing something!?

FYI Srever name & port are not required for this Wed Service. 

JSONPOST
 Set Body = ##class(%ZEN.proxyObject).%New()
 Set Body.Id = "123"
 Set Body.PayerEmailAddress = "email"
 Set Body.PayerBusinessHoursPhoneNumbe = "PayerBusinessHoursPhoneNumbe"
 Set Body.PayerAustralianBusinessNumbe = "PayerAustralianBusinessNumbe"
 Set Body.PayerWithholdingPayerNumber = "PayerWithholdingPayerNumber"

 Set Request= ##class(%Net.HttpRequest).%New()
 Set Request.Location = "https://devtest.altus.net.au/STP_IF/rest/Employee/"
 Set Status = ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(Request.EntityBody, Body)
 Set Status = Request.Post()

it is also a pain to look through and understand Cache documentation in many case! for example, I've some examples on JSONobjects and arrays and try to replicate them but they came up with syntax errors eg. 

SET JArray=["somthing "] 

OR

Set Array1 = ##class(%Library.DynamicArray).%New()
 SET Array1=[]

so in both cases Array1 or JArray is not understanding [] so should be including or extending a classe(s) or ...etc 
 

I'm basically looking to handcraft the Body.%ToJSON() content to to be contained in [] so I can post it because this what Receiving Web Service is expecting the message to be like. 

so looking for somthing like : 

Set MyMessage="[" _Body.%ToJSON()_"]" 

but its not working for me at the moment!?

 

Thanks

SET JArray=["somthing "] 

OR

Set Array1 = ##class(%Library.DynamicArray).%New()
 SET Array1=[]

so in both cases Array1 or JArray is not understanding [] so should be including or extending a classe(s) or ...etc 

That's available from version 2016.2. Refer to your local documentation or online documentation for 2014 version.

FYI Srever name & port are not required for this Wed Service. 

It's not server name - it's host and it's required. You also need to specify HTTPS and SSLConfig.

If I execute your code in test mode (  Set Status = Request.Post(,1) ) I receive:

POST /https%3A//devtest.altus.net.au/STP_IF/rest/Employee/ HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; Cache;)
Host: localhost
Accept-Encoding: gzip
Content-Length: 239
Content-Type: text/html; charset=UTF-8
 
{
        "Id":123,
        "PayerAustralianBusinessNumbe":"PayerAustralianBusinessNumbe",
        "PayerBusinessHoursPhoneNumbe":"PayerBusinessHoursPhoneNumbe",
        "PayerEmailAddress":"email",
        "PayerWithholdingPayerNumber":"PayerWithholdingPayerNumber"
}

You should probably modify your code like this this:

ClassMethod Test(test As %String(VALUELIST="0,1,2") = 1)
{
 Set Body = ##class(%ZEN.proxyObject).%New()
 Set Body.Id = "123"
 Set Body.PayerEmailAddress = "email"
 Set Body.PayerBusinessHoursPhoneNumbe = "PayerBusinessHoursPhoneNumbe"
 Set Body.PayerAustralianBusinessNumbe = "PayerAustralianBusinessNumbe"
 Set Body.PayerWithholdingPayerNumber = "PayerWithholdingPayerNumber"

 Set Request= ##class(%Net.HttpRequest).%New()
 Set Request.Server = "devtest.altus.net.au"
 
 Set Request.Location = "STP_IF/rest/Employee/"
 Set Request.Https = $$$YES
 Set Request.SSLConfiguration = "YourSSLConfig"
 Set Status = ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(Request.EntityBody, Body)
 Set Status = Request.Post(,test)
}

Where  SSLConfiguration is the name of your ssl config. Afterwards with test=1 I get this:

POST /STP_IF/rest/Employee/ HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; Cache;)
Host: devtest.altus.net.au
Accept-Encoding: gzip
Content-Length: 239
Content-Type: text/html; charset=UTF-8
 
{
        "Id":123,
        "PayerAustralianBusinessNumbe":"PayerAustralianBusinessNumbe",
        "PayerBusinessHoursPhoneNumbe":"PayerBusinessHoursPhoneNumbe",
        "PayerEmailAddress":"email",
        "PayerWithholdingPayerNumber":"PayerWithholdingPayerNumber"
}

And the response with test=2 is as follows:

HTTP/1.1 405 Method Not Allowed
ALLOW: GET
CACHE-CONTROL: no-cache
CONNECTION: keep-alive
CONTENT-LENGTH: 73
CONTENT-TYPE: application/json; charset=utf-8
DATE: Fri, 05 Jan 2018 08:16:20 GMT
EXPIRES: -1
PRAGMA: no-cache
SERVER: Microsoft-IIS/8.5
 
{"Message":"The requested resource does not support http method 'POST'."}

You should check the API docs for correct location (or HTTP verb)

I'm basically looking to handcraft the Body.%ToJSON() content to to be contained in []

Wrap Body in %ListOfObjects for that:

Set List = ##class(%ListOfObjects).%New()
Do List.Insert(Body)
Set Status = ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(Request.EntityBody, List)

And your request body would look like this:

[ {
                "Id":123,
                "PayerAustralianBusinessNumbe":"PayerAustralianBusinessNumbe",
                "PayerBusinessHoursPhoneNumbe":"PayerBusinessHoursPhoneNumbe",
                "PayerEmailAddress":"email",
                "PayerWithholdingPayerNumber":"PayerWithholdingPayerNumber"
        }
]

Hi Eduard,

I've changed the code as below (sorry, location :"/STP_IF/rest/Employee/Create") , but if I don' t provide HTTPS & SSLConfig I get the following error : "{"Errors":["HTTPS connection required."],"StatusCode":403}"

The REST API that we connecting to has no SSL configuration required, so and if I set Https=1 (because Https=$$$YES is not supported in ensemble 2014) and set Request.SSLConfiguration=""  or not setting SSLConfig at all I get this error: "SSL/TLS configuration '' is not activated."

so is there a way to get it working with SSLConfig, because in many case or programming languages SSL is rather optional?

 Set List = ##class(%ListOfObjects).%New()
 Do List.Insert(Body)
 Set Request= ##class(%Net.HttpRequest).%New()
 Set Request.Server = "devtest.altus.net.au"
 Set Request.Location = "/STP_IF/rest/Employee/Create"
 //S Request.ProxyAuthorization="SVRWSVMhME4yOlVyYW51czY="
 Set Request.Https=1
 set Request.SSLConfiguration=""
 Set Status = ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(Request.EntityBody, List)
 Set Status = Request.Post(,2)
 

with Request.Post() there is only brief documentation on it, so my understanding it test=1 means post to device and 2 send post and get response and not sure what rest 0 or 1 means as the doc doesn't mention it!?

and I'm guessing that location in Post method is optional given that we set Set Request.Location = "/STP_IF/rest/Employee/Create"

 

Thanks Eduard

so is there a way to get it working with SSLConfig

As I said:

Where  SSLConfiguration is the name of your ssl config.

You need to create a SSL config. Docs explain how.

 test 0 or 1 means as the doc doesn't mention it!?

Test values

  • 0 - send as usual
  • 1 - do not send, output request to the current device
  • 2- send the request and output response to the current device

location in Post method is optional given that we set Set Request.Location = "/STP_IF/rest/Employee/Create"

Yes, it's enough to specify Location property.

Ahhh, I remember that, I did one before for sending emails utility.

I've created one SSL Config (just s Simple one with just s name and kept default) and my code now is :

 Set List = ##class(%ListOfObjects).%New()
 Do List.Insert(Body)
 Set Request= ##class(%Net.HttpRequest).%New()
 Set Request.Server = "devtest.altus.net.au"
 Set Request.Location = "/STP_IF/rest/Employee/Create"
 //S Request.ProxyAuthorization="SVRWSVMhME4yOlVyYW51czY="
 Set Request.Https=1
 Set Request.SSLConfiguration="TLS"
 Set Status = ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject(Request.EntityBody, List)
 Set Status = Request.Post(,2)
but I get this error :  
{"Errors":["The request entity's media type 'text/html' is not supported for this resource."],"StatusCode":415}

and by the way, is Set Request.Https=1 correct given that Set Request.Https=$$$YES not supported in Ensemble 2014?

 

Thanks

and by the way, is Set Request.Https=1 correct given that Set Request.Https=$$$YES not supported in Ensemble 2014?

Yes, it's the same thing $$$YES macro resolves into 1.

but I get this error :  
{"Errors":["The request entity's media type 'text/html' is not supported for this resource."],"StatusCode":415}

Specify content type. For example:

Set Request.ContentType = "application/json"

or whatever content type the api requires.

WoooHooo, that worked, thanks Eduard.

but by the way, I downloaded Cache 2017.1 and Set Request.Https=$$$YES the same syntax error !? just to mention .

 

Thanks again Eduard for your prompt responses have a good day

Hi Eduard,

 

Not sure is I can still ask this in this current Post or I should just start a new post, but simply, given that we still have some clients running on Cache/ensemble 2008.2.6.964 and %ZEN.Auxiliary.jsonProvider is not available, is there a Patch that can be installed for JSON provider or they only option is to upgrade those clients to 2014?

Thanks 

%ZEN.Auxiliary.jsonProvider is available since 2009.2. You'll need to upgrade.

Hi, Rochdi!

This is better to be in a new question: how to work with JSON in Caché versions earlier 2014.