Accepting JSON object in body of HTTP API Request

delphi

(Stuart Clennett) #1

Hi,

I’m trying to implement a REST API on existing custom Delphi server.

I need to accept some data via the body in the form of a JSON object. I have got as far as the following code:

TLoginRequest = class(TROComplexType)
private
	fpassword: ROUTF8String;
	fusername: ROUTF8String; // this will be the body of the DoSessionLogin
public
	{$IFDEF RO_RTTI_Support} [ROSerializeAsUTF8String] {$ENDIF}
	property username : ROUTF8String read fusername write fuserName;
	{$IFDEF RO_RTTI_Support} [ROSerializeAsUTF8String] {$ENDIF}
	property password : ROUTF8String read fpassword write fpassword;
end;

and then the service declares the following:

[ROService]
TLoginService = class(TSimpleLoginService)
public
  [ROServiceMethod]
  [ROCustom('HttpApiPath','sessions/')]
  [ROCustom('HttpApiMethod','POST')]
  [ROCustom('HttpApiResult', '201')] // 201 = created
  function createSession(loginRequest : TLoginRequest): Userinfo;
  // ...
end;

The problems I have are:

  1. The api at localhost:8099/api shows the TLoginRequest, but doesn’t show any attributes for the TLoginRequest in the definitions object.

    ,
    TLoginRequest: {
    type: “object”,
    properties: { }
    },

  2. When I use postman to call the method with the JSON as the body of the request, the createSession method itself receives a TLoginRequest object with empty params.

  3. If the createSession method fails, I raise a 403 as follows:

    EROHttpApiException.Create(HTTP_403_code, HTTP_403_status);

This code is called, but the method still returns 201 to Postman.

Thanks

Stuart


(EvgenyK) #2

Hi,

specify username & password as published properties instead of public ones

check that you have raise here like

raise EROHttpApiException.Create(HTTP_403_code, HTTP_403_status);

(Stuart Clennett) #3

Hi Evgeny,

Thanks for the reply.

The properties are now showing up in the API description & the exception is now being raised okay.

I still have the problem of getting the JSON data from postman into the createSession. When I debug the server, the loginRequest.username and loginRequest.password are both empty strings.

This is my PostMan setup:

Thanks


(EvgenyK) #4

try to use CURL:

>curl -X POST "http://localhost:8099/MyPath/sessions/" -H  "accept: application/json" -H  "content-type: application/json" -d "{  \"loginRequest\": {    \"password\": \"password\",    \"username\": \"user\"  }}"

Forbidden
>curl -X POST "http://localhost:8099/MyPath/sessions/" -H  "accept: application/json" -H  "content-type: application/json" -d "{  \"loginRequest\": {    \"password\": \"user\",    \"username\": \"user\"  }}"
"logged"

this is for

function TSampleService.createSession(loginRequest: TLoginRequest): ROUTF8String;
begin
  if loginRequest.username <> loginRequest.password then raise EROHttpApiException.Create(HTTP_403_code, HTTP_403_status);
  result := 'logged';
end;

(Stuart Clennett) #5

Hi Evgeny,

I didn’t use curl, but looking at your command line, I changed my PostMan data to:

{
  "loginRequest": {
    "username": "user2",
    "password": "letmein98"
  }
}

(added in the parent “loginRequest” attribute which wasn’t there before. The username and password properties are coming through now - thanks.


ONE more question please - what do I need to do in my HTTP API methods to ensure the SessionID is valid? I have RequiresSession to true on my services.

Do I need to pass SessionID as the first param to all methods?

Thanks in advance

Stuart


(EvgenyK) #6

I’m using swagger-editor and it generated curl requests for me.
it can be usable for you too.

as for SessionID: it was returned as Access-Token header

< HTTP/1.1 200 OK
< Connection: close
< Content-Type: application/json; charset=utf-8
< Content-Length: 0
< Date: Tue, 05 Mar 2019 14:10:09 GMT
< Accept-Encoding: gzip, identity
< Access-Token: {7FCBCC75-846B-41F0-BDD7-68052C4AEDE2}

for using this token, you should pass it as http header in your request:

>curl -verbose -X POST "http://localhost:8099/api/test/Sum" -H  "accept: application/json" -H  "Access-Token: {7FCBCC75-846B-41F0-BDD7-68052C4AEDE2}" -H  "content-type: application/json" -d "{  \"A\": 1,  \"B\": 2}"
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8099 (#0)
> POST /api/test/Sum HTTP/1.1
> Host: localhost:8099
> User-Agent: curl/7.56.0
> Referer: rbose
> accept: application/json
> Access-Token: {7FCBCC75-846B-41F0-BDD7-68052C4AEDE2}
> content-type: application/json
> Content-Length: 19
* upload completely sent off: 19 out of 19 bytes
< HTTP/1.1 200 OK
< Connection: close
< Content-Type: application/json; charset=utf-8
< Content-Length: 1
< Date: Tue, 05 Mar 2019 14:13:51 GMT
< Accept-Encoding: gzip, identity
< Access-Token: {7FCBCC75-846B-41F0-BDD7-68052C4AEDE2}
3
* Closing connection 0

(Stuart Clennett) #7

Hi Evgeny,

Very useful information - thanks very much.

I will try curl, I promise :wink:

Thanks