#1 2023-03-06 14:00:11

mrbar2000
Member
From: Brazil
Registered: 2016-10-26
Posts: 59

SOA by Interfaces with custom HTTP Status

Hi All,

I see that when implementing services interface based the framework always return 200.
But we whould like return others httpstatus.

then we discover TServiceCustomAnswer. this resolve the httpstatus problem, but this return do not accept parameters out neither var

sample. What i would like do:

function TProjetoService.GetProjetoPaineis(out pProjeto: TOrmProjeto): TServiceCustomAnswer;
begin
  if not FRestOrm.Retrieve(pProjeto.Id, pProjeto) then
    Result := ReturnError(Format('(%s) '+cErrorRecordNotFound, [GetClassName]), HTTP_NOTFOUND)
  // else following the course, will return 200 ok!!!!
end;

function TServiceBase.ReturnError(const pErrorMessage: RawUTF8; pStatus: cardinal): TServiceCustomAnswer;
var
  vError: Variant;
begin
  TDocVariant.New(vError);
  vError.ErrorMessage := pErrorMessage;
  vError.StatusCode := pStatus;
  Result.Content := VariantSaveJson(vError);
  Result.Status := pStatus;
end;


How we can do this? What the recomendation?

Last edited by mrbar2000 (2023-03-06 14:01:48)

Offline

#2 2023-03-06 14:51:20

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

Re: SOA by Interfaces with custom HTTP Status

You are right, by design, interface-based services always return 200, as part of the routing scheme.
This is expected by the mORMot client.

If you want something more complex, for a non mORMot client, only method-based services are to be used.

Offline

#3 2023-03-06 15:45:10

mrbar2000
Member
From: Brazil
Registered: 2016-10-26
Posts: 59

Re: SOA by Interfaces with custom HTTP Status

Problem with this is that we have to treat all input/output parameters of service method, getting of Ctx. very hard work!

There are some other way?

Offline

#4 2023-03-06 16:50:05

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

Re: SOA by Interfaces with custom HTTP Status

Not yet.

Offline

#5 2023-03-07 06:52:37

igors233
Member
Registered: 2012-09-10
Posts: 234

Re: SOA by Interfaces with custom HTTP Status

> Problem with this is that we have to treat all input/output parameters of service method, getting of Ctx. very hard work!

Note for parsing input params you can use Ctx.GetInputAsTDocVariant to receive params as JSON document which is easy to parse.
Also when sending result you can do that as JSON which is easy to write/read on both server and client side.

Offline

#6 2023-03-07 11:01:26

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

Re: SOA by Interfaces with custom HTTP Status

Since it is not the first time this feature is asked, I have implemented it.

Please try
https://github.com/synopse/mORMot2/commit/7d36f145

Now you can write:

function TProjetoService.GetProjetoPaineis(out pProjeto: TOrmProjeto): TServiceCustomStatus;

This TServiceCustomStatus type is just a specific kind of cardinal parameter.
But now the result value (in range 200..599) will be propagated as HTTP response code.
It won't change anything for mORMot client/server communication - just for non-mORMot HTTP clients, they will be able to check the HTTP response code.

Offline

#7 2023-03-07 20:52:21

mrbar2000
Member
From: Brazil
Registered: 2016-10-26
Posts: 59

Re: SOA by Interfaces with custom HTTP Status

Very fast, Very thanks.

Offline

#8 2023-03-14 15:09:03

mrbar2000
Member
From: Brazil
Registered: 2016-10-26
Posts: 59

Re: SOA by Interfaces with custom HTTP Status

Hi, I make some changes in TServiceCustomStatus
and put a PR #160

What did u think?
Are u see some problem in my changes?

Offline

#9 2023-03-14 16:08:59

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

Re: SOA by Interfaces with custom HTTP Status

Please see my comments in the PR.

I see several problems to your proposition.
Please discuss here. wink

Offline

#10 2023-03-15 14:27:40

mrbar2000
Member
From: Brazil
Registered: 2016-10-26
Posts: 59

Re: SOA by Interfaces with custom HTTP Status

Good Morning Arnold,

I thought TServiceCustomStatus was only for non mormot clients.

Atualmente o mormot traz no result uma matriz com valores diversos. E não é possível ler isso de clientes não mormot. Veja isso.

TPaineis = array or TPainel

function BuscaPaineis(idProject: integer; out paineis: TPaineis): boolean;

// if I put an idProject that doesn't exist, for example, a Json arrives in this format:
{
  "result" = [ [], false ]
}

// if I put an idProject that exists for example a Json arrives in this format:
{
  "result" = [ [{"painel": 'painel1'}, {"painel": 'painel1'}],  true ] 
}

A non-mormot client is expecting just an array of TPainel. Which is not the case with the true and false into array.

An example response that mormot could return and handle without impacting applications that use interface-based SOA could look like this:

function BuscaPaineis(idProject: integer; out paineis: TPaineis): boolean;

{
  "result" = [{"painel": 'painel1'}, {"painel": 'painel1'}],
  "return" = true
}

I will further detail the problems I am trying to solve as I want to work with interface based SOA. But I need the mormot server to return the JSON in a way that can be read by any 3rd party application.

1) Return the custom HTTP code
2) The returned JSON should follow a pattern for when the result is 200..399.
3) When the return is 400..599 I need the returned JSON to follow an exception pattern with the proper error message. This type really should not be an exception, even though they are expected errors. They should not be logged or handled by the framework.

When I use TServiceCustomStatus I can return the statuscode that I want, great!
But when I return a code between 400...599 I have to return a Json with the reason for this error.
So I thought of TServiceCustomStatus as a record. And I adjusted the code so that anyone who wants to use Mormot and is not using a Mormot client.

Maybe a way to standardize this would be that every return from mormot would return

{ 
    "<result> or <classname>": <Jsonobject> or <JsonArray> 
    "errormessage": "<empty> or <custom error message>"  <<< not out parameter but a TServiceCustomStatus.ErroMessage field 
    "return" : <null is procedure> or <value of function result>   <<< if function is TServiceCustomStatus then TServiceCustomStatus.Status
}

Without losing the cardinal TServiceCustomStatus obviously. HTTPStatus code would return TServiceCustomStatus.Status too.

I'm asking this because my frontend tool (as well as many others) already evaluates the http statuscode to be able to direct the workflow to a success or error routine.

We don't always have control over the frontend that will be using our API, and some of these clients don't have the facility to change their programming.
I know someone here may say that it is the clients that should implement according to the API specification, but I have clients that use no-code tools that just receive the json and treat this json according to the returned http statuscode.

In summary. Your mormot clients would not have to change their programming at all, because if I have the following methods in the interface they would return the following json:

function TABC.FindOrder(Id: Integer; out Order: TOrder; out Items: TItems): TServiceCustomStatus;
{ 
    "output1" or "order": { "id": 1, ... } 
    "output2" or "items": [{ "id": 10, ... }, { "id": 11, ... }, { "id": 12, ... }]
    "errormessage": ""
    "return" : 200  <<<< the same of HTTPStatus code returned
}

function TABC.FindOrder(Id: Integer; out Order: TOrder; out Items: TItems): boolean;
{ 
    "output1" or "order": { "id": 1, ... } 
    "output2" or "items": [{ "id": 10, ... }, { "id": 11, ... }, { "id": 12, ... }]
    "errormessage": ""
    "return" : true <<<< HTTPStatus code always 200 if result <> TServiceCustomStatus
}

To internaol SOA process, "errormessage" field would be ignored unless the programmer put an out errormessage in the parameters.

Offline

#11 2023-03-18 13:15:55

mrbar2000
Member
From: Brazil
Registered: 2016-10-26
Posts: 59

Re: SOA by Interfaces with custom HTTP Status

What u think Arnold?

What i can see about the code, all workflow abou soa via interfaces is internal. Then i think this idea is viable.

Offline

#12 2023-03-28 12:04:54

mrbar2000
Member
From: Brazil
Registered: 2016-10-26
Posts: 59

Re: SOA by Interfaces with custom HTTP Status

Arnold, I would like to thank you for your comments here and apologize for the lack of knowledge in the framework, I'm still new to mormot, but I'll get there. Digging around the framework I discovered the properties:

TServiceFactoryServer's SetWholeOption([???])
optResultAsJsonObjectWithoutResult or optResultAsJsonObject

I just put the optResultAsJsonObjectWithoutResult option and the json I wanted was already returned the way I needed it.

function Busca(pId: Int64; var abc: TDTOProjeto; out pProjeto: TDTOProjeto; out pPaineis: TDTOPaineis): TServiceCustomStatus;

{
    "abc": {
        "RowID": 1,
        "Nome": "Projeto c",
        "DataCriacao": "2023-03-18T12:34:09",
        "UltimaAlteracao": "2023-03-18T12:34:09",
        "IdCriador": 5,
        "Paineis": []
    },
    "pProjeto": {
        "RowID": 1,
        "Nome": "Projeto c",
        "DataCriacao": "2023-03-18T12:34:09",
        "UltimaAlteracao": "2023-03-18T12:34:09",
        "IdCriador": 5,
        "Paineis": [
            {
                "RowID": 1,
                "Nome": "painel a",
                "DataCriacao": "2023-03-20T10:08:48",
                "UltimaAlteracao": "2023-03-20T10:08:48",
                "IdCriador": 5,
                "IdProjeto": 1
            }
        ]
    },
    "pPaineis": [
        {
            "RowID": 1,
            "Nome": "painel a",
            "DataCriacao": "2023-03-20T10:08:48",
            "UltimaAlteracao": "2023-03-20T10:08:48",
            "IdCriador": 5,
            "IdProjeto": 1
        }
    ],
    "Result": 0
}

long live the mormot!

Offline

Board footer

Powered by FluxBB