Passing json to httpapi rosdk REST server

From the examples I’ve seen, I see that passing parameters works fine. And, while I haven’t tried it, passing json with a defined object like {obj:…} works. But I just need some plain old json to be passed to my function. Case in point is twilio which makes a get or post call to my url and passes the json similar to this:

{
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "annotation": null,
  "answered_by": null,
  "api_version": "2010-04-01",
  "caller_name": null,
  "date_created": "Tue, 31 Aug 2010 20:36:28 +0000",
  "date_updated": "Tue, 31 Aug 2010 20:36:44 +0000",
  "direction": "inbound",
  "duration": "15",
  "end_time": "Tue, 31 Aug 2010 20:36:44 +0000",
  "forwarded_from": "+141586753093",
  "from": "+15017122661",
  "from_formatted": "(501) 712-2661",
  "group_sid": null,
  "parent_call_sid": null,
  "phone_number_sid": "PNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "price": "-0.03000",
  "price_unit": "USD",
  "sid": "CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "start_time": "Tue, 31 Aug 2010 20:36:29 +0000",
  "status": "completed",
  "subresource_uris": {
    "notifications": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Notifications.json",
    "recordings": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Recordings.json",
    "feedback": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Feedback.json",
    "feedback_summaries": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/FeedbackSummary.json",
    "payments": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Payments.json",
    "events": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Events.json"
  },
  "to": "sip:UserA@Trunk1.sip.us1.twilio.com",
  "to_formatted": "sip:UserA@Trunk1.sip.us1.twilio.com",
  "trunk_sid": null,
  "uri": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Calls/CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.json",
  "queue_time": "1000"
}

I really just need to know how I can access it as a whole. I don’t need it to be parsed automatically into an object or anything.
With that said, I guess I’m also trying to get to any of the headers being passed.
Thanks for any help you can give.

Hello
What is your server platform (is it .NET or Delphi)?

Sorry, forgot. Delphi 10.4

Hi,

Have you tried to pass this JSON string as usual string or as binary in POST request ?

Using postman, json data is usually in the body, correct? So I really need access to the body, headers. I just don’t know how that’s done here in the service function.

Hi,

Check Using OnCustomResponseEvent in a ROSDK Server snippet.
here you have access to everything - headers and body.

Note: this event handles only unknown requests, like http://localhost:8099/something_unknown/MyMethod

But I know the route. I just need access to headers and body. The json coming from twilio is nothing special, just a payload of data that I need to access. No different than uploading a file or anything else. Just need to know how to access it.

I looked at the topic with passing complex types:
{
“obj”:{
“Name”:“Deepak”,
“MName”:“Kumar”,
“LName”: “Jain”
}
}

It relies having the variable name passed as a parameter. The problem with most REST calls, is that they don’t care what the variable name is. As you see from the json data I posted, there is no “variable” wrapper, it is just data. There has to be an easy way to get it without rebuilding a routing system.

hi,

Can you show a simple CURL request to DA server and what you want to receive?
you can drop email with details to support@ for keeping privacy

To simplify, I added my test information with the curl from Swagger. You can see I post Addr, the defined variable for the complex type. BUT, I am supporting a call from an outside system that I have no control over so they will not and cannot send the variables within the “Addr” variable. They would send something like this with just the field data in json format. Therefore I need to access the body, get the json myself, and pick the variables that I want and need to use.

Example of what I would be receiving-Plain old json - No parameter name (“Addr”):

{
    "Address1": "123 Main St",
    "Address2": "STE B",
    "City": "New York",
    "State": "NY",
    "ZipCode": "10025"
  }

curl from Swagger:

curl -X 'POST' \
  'http://localhost:8099/api/readme' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "Addr": {
    "Address1": "123 Main St",
    "Address2": "STE B",
    "City": "New York",
    "State": "NY",
    "ZipCode": "10025"
  }
}'

RESPONSE:

{
  "Address": {
    "Address1": "123 Main St",
    "Address2": "STE B",
    "City": "New York",
    "State": "NY",
    "ZipCode": "10025"
  },
  "Age": 0,
  "FirstName": "",
  "LastName": "",
  "Sex": ""
}

Definitions:

  TAddress = class(TROComplexType)
  private
    fZipCode: String;
    fState: String;
    fAddress2: String;
    fAddress1: String;
    fCity: String;
  published
    [ROSerializeAsAnsiString]
    property Address1: String read fAddress1 write fAddress1;
    [ROSerializeAsAnsiString]
    property Address2: String read fAddress2 write fAddress2;
    [ROSerializeAsAnsiString]
    property City: String read fCity write fCity;
    [ROSerializeAsAnsiString]
    property State: String read fState write fState;
    [ROSerializeAsAnsiString]
    property ZipCode: String read fZipCode write fZipCode;
  end;

  TPersonx = class(TROComplexType)
  private
    fFirstName: String;
    fLastName: String;
    fAge: Integer;
    fSex: String;
    FAddress: TAddress;
    procedure SetAddress(const Value: TAddress);
  public
    constructor Create;override;
    destructor Destroy;override;
  published
    [ROSerializeAsAnsiString]
    property FirstName: String read fFirstName write fFirstName;
    [ROSerializeAsAnsiString]
    property LastName: String read fLastName write fLastName;
    property Address:TAddress read FAddress write SetAddress;
    property Age: Integer read fAge write fAge;
    [ROSerializeAsAnsiString]
    property Sex: String read fSex write fSex;
  end;

Method:

    [ROServiceMethod]
    [ROCustom('HttpApiPath','readme')]
    [ROCustom('HttpApiMethod','POST')]
    function UseReadAddress(Addr: TReadAddress): TPersonx;

Hi,

As I see, you would like to handle

  {
    "Address1": "123 Main St",
    "Address2": "STE B",
    "City": "New York",
    "State": "NY",
    "ZipCode": "10025"
  }

instead of

{
  "Addr": {
    "Address1": "123 Main St",
    "Address2": "STE B",
    "City": "New York",
    "State": "NY",
    "ZipCode": "10025"
  }
}

is it correct?

if yes, you can use OnCustomResponseEvent event and modify json string as

// extracting data
SetLength(s, aRequestStream.Size);
aRequestStream.Read(Pointer(s)^, Length(s));
// modify request
s := '{"Addr":' + s + '}';
// write back
aRequestStream.Size := 0;
aRequestStream.Write(Pointer(s)^, Length(s));

// 2. Invoke service method 
lMessage:= (ROJsonMessage as IROMessageCloneable).Clone;
MainProcessMessage(lMessage,atransport,aRequestStream,aResponseStream,op);

write it back to request stream and allow to process changed request.

We’re getting close and it’s ok if I have a few calls that need help along the way.
If I leave the call to localhost:8099/api/readme - it goes automatically to the service call
So we have to modify the call to be localhost:8099/xxxx/readme so the OnCustomResponseEvent will fire.

Now we need to invoke the right method.

In the sample code: it shows:
SetLength(s, aRequestStream.Size);
aResponseStream.Position := 0;
aRequestStream.Read(Pointer(s)^, Length(s));

// modify data in some way
s := ‘__MessageType=Message&__InterfaceName=MyService&’+s;

// write updated data back to stream
aRequestStream.Size := 0;
aRequestStream.Write(Pointer(s)^, Length(s));

So I changed “MyService” to “UseReadAddress” since that is the name of my service but it is trying to convert the first _ to an integer and failing.
s := ‘__MessageType=Message&__InterfaceName=UseReadAddress&{“Addr”:’ + s + ‘}’;

If I do just as you said:
s := ‘{“Addr”:’ + s + ‘}’;
The process doesn’t know what to invoke.

Hi,
pls review testcase: 24998.zip (108.8 KB)

curl requests:

curl -v -X POST "http://localhost:8099/api/readme" -H  "accept: application/json" -H  "content-type: application/json" -d "{  \"Addr\": {    \"Address1\": \"123 Main St\",    \"Address2\": \"STE B\",    \"City\": \"New York\",    \"State\": \"NY\",    \"ZipCode\": \"10025\"  }}"

and

curl -v -X POST "http://localhost:8099/xxxx/readme" -H  "accept: application/json" -H  "content-type: application/json" -d "{    \"Address1\": \"123 Main St\",    \"Address2\": \"STE B\",    \"City\": \"New York\",    \"State\": \"NY\",    \"ZipCode\": \"10025\"  }"

That little change in the custom event worked great! Thank you.