#1 2019-06-17 15:22:16

tomek
Member
Registered: 2017-10-24
Posts: 46

Raising http 400 in Interface-Based Service

Hi
Is it possible to override mormot's response and return Http 400 "Bad request" in Interfaced-based service? (In case if we want to make additional validation of incoming parameters).

Regards, Tomek

Offline

#2 2019-06-18 01:24:43

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 332

Re: Raising http 400 in Interface-Based Service

Try:

CurrentServiceContextServer.Error(400,'error message');

I don't remember the exact sintax.


Esteban

Offline

#3 2019-06-18 06:40:07

tomek
Member
Registered: 2017-10-24
Posts: 46

Re: Raising http 400 in Interface-Based Service

Hi
I've tried, but it doesn't seem to work, it still returns 200:

function TRemoteSrv.Test(aParams: UTF8String): UTF8String;
begin
  //Result := 'Test(' + aParams + ')';
  //ServiceContext.Request.Error('Wrong param value', 400);
  // CurrentServiceContextServer.... no "Error" method
  CurrentServiceContext.Request.Error('Wrong param value', 400);
end;

Regards, Tomek

Last edited by tomek (2019-06-18 06:40:33)

Offline

#4 2019-06-18 13:48:44

macfly
Member
From: Brasil
Registered: 2016-08-20
Posts: 374

Re: Raising http 400 in Interface-Based Service

Try (not tested):

CurrentServiceContext.Request.Returns('Wrong param value', 400);

Offline

#5 2019-06-18 13:50:11

xalo
Member
Registered: 2016-09-22
Posts: 32

Re: Raising http 400 in Interface-Based Service

Hi,
If I'm not wrong, the way to return custom response it's via TServiceCustomAnswer record type.
Please check related section in documentation for further details.

Offline

#6 2019-06-19 18:41:13

macfly
Member
From: Brasil
Registered: 2016-08-20
Posts: 374

Re: Raising http 400 in Interface-Based Service

I tested it and it really does not work.

At some point of TServiceFactoryServer.ExecuteMethod the status is forced to 200.

60129  Ctxt.Call.OutStatus := HTTP_SUCCESS;

A TServiceCustomAnswer should be used as mentioned by @xalo.


The problem of this in my view is that it loses the standard functionality and it is mandatory to use this type of result.

It may be best to return status 200 and error details in JSON. Something like
{"error": "No validated", "code:" 123}

Offline

#7 2019-06-20 07:56:12

pvn0
Member
From: Slovenia
Registered: 2018-02-12
Posts: 210

Re: Raising http 400 in Interface-Based Service

Don't use TServiceCustomAnswer, if you feel like that's what you need then use method based services instead, that will give you all the customization you want.

Instead, like @macfly said, your service defined interface methods should have an out parameter specifying your custom result code :

 procedure DoSomething(const X,Y,Z : Integer; out Result: TResult); // where TResult is an Enum type   

Http codes are great for connection, session status, anything else, introduce your own.

Offline

#8 2019-06-20 11:24:57

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,206
Website

Re: Raising http 400 in Interface-Based Service

pnv0 is in the right way, from my point of view. smile

Ensure you read https://synopse.info/files/html/Synopse … l#TITL_165

In short: for interface-based services, don't rely on HTTP error codes, but define some enumeration types, used to return the state/error of the process.
And set the first enumerate (mapped as 0 in JSON) as "successful state" - this would be the default value, e.g. for mocking.

If you want to have some HTTP status code returned, use method-based services - or TServiceCustomAnswer with interface-based services, but it is not the best pattern just for handling errors, since you would need manual marshalling of the returned JSON, and generate week RTTI information (not good for the documentation, or the client code generation).

Offline

#9 2019-06-21 06:31:34

tomek
Member
Registered: 2017-10-24
Posts: 46

Re: Raising http 400 in Interface-Based Service

Thank you all for tips and possible solutions.
The problem is, that server is made for third party client, and client side developers are quite reluctant to interpreting custom answers with http 200.

Regards, Tomek

Offline

#10 2019-06-21 14:33:06

Shadownildo
Member
From: Brazil
Registered: 2018-10-10
Posts: 36

Re: Raising http 400 in Interface-Based Service

tomek wrote:

Thank you all for tips and possible solutions.
The problem is, that server is made for third party client, and client side developers are quite reluctant to interpreting custom answers with http 200.

Regards, Tomek

If i understood it right, you want to do something like this ?

 if FConnection.SetUser(AAuthSettings.GetUSerName, AAuthSettings.GetPassWord) then
  begin
    aStatus := FConnection.CallBackGet(
      'Autentication', [
        'Id', AAuthSettings.GetId.ToString
      ], aOut
    );

    Result := (aStatus = 200);
    case aStatus of
      200:
      begin
        Result := True;
        AMessage := 'OK';
      end;
      400:
      begin
        Result := False;
        AMessage := 'Conection limit!';
      end;
      401:
      begin
        Result := False;
        AMessage := 'Route Blocked';
      end

Offline

#11 2019-06-21 18:18:31

macfly
Member
From: Brasil
Registered: 2016-08-20
Posts: 374

Re: Raising http 400 in Interface-Based Service

A proposal to allow return an error status  is to use exceptions.
Since a status error is being returned conscientiously, I believe no pattern is being broken.

Something like:

ESynServiceJSONException = class(ESynServiceException)...
   contructor Create(Status, AMessage: RawUtf8; Result : Variant);
end;

Then...

function TRemoteSrv.Test(aParams: UTF8String): UTF8String;
begin
   if not Validated(...) then
      raise ESynServiceJSONException.Create(400, 'Not validated', _Obj(['name','Can not be empty'])); 
end;

Produces

// 400 Not validated

{"result":{
  "name":"Can not be empty"
}}

Last edited by macfly (2019-06-21 18:33:46)

Offline

Board footer

Powered by FluxBB