You are not logged in.
As stated here, it seems impossible:
http://synopse.info/forum/viewtopic.php?id=1536
I've been working on a web service API for consumption by others via JavaScript, etc. using Interface Based Services, but without support for custom status codes, the project cannot move forward.
Is there any way at all to return a custom HTTP Status code for Interface Based Services?
In the above post, you said:
By now, it expects HTML_SUCCESS (200) on the client side for any success full process.
See e.g. TServiceFactoryClient.InternalInvoke().So allowing any custom code may be very difficult, and break the default expected behavior of the JSON-RPC protocol.
Note that if you raise an exception, it will return an error 500 to the client.
I'm wondering how this would break existing code. Why would it be a problem for the client to continue to require HTML_SUCCESS (200), but fail on a non-200 status code?
I changed the following code in mORMot.pas to enable returning a status code in TServiceCustomAnswer, which seems to work.
Note that if the Status is 0, it will default to HTML_SUCCESS (200).
TServiceCustomAnswer = record
Status: Cardinal; // <-----------------
Header: RawUTF8;
Content: RawByteString;
end;
function TServiceMethod.InternalExecute(Instances: array of pointer;
Par: PUTF8Char; Res: TTextWriter; var aHead: RawUTF8; var aStatus: Cardinal; // <-----------------
Options: TServiceMethodOptions; ResultAsJSONObject: boolean;
BackgroundExecutionThread: TSynBackgroundThreadProcedure): boolean;
procedure TServiceFactoryServer.ExecuteMethod(Ctxt: TSQLRestServerURIContext);
[…]
Ctxt.ServiceResultStart(WR);
try
if optExecLockedPerInterface in fExecution[Ctxt.ServiceMethodIndex].Options then
EnterCriticalSection(fInstanceLock);
if not fInterface.fMethods[Ctxt.ServiceMethodIndex].InternalExecute(
[PAnsiChar(Inst.Instance)+entry^.IOffset],Ctxt.ServiceParameters,WR,
Ctxt.Call.OutHead,Ctxt.Call.OutStatus, // <-----------------
fExecution[Ctxt.ServiceMethodIndex].Options,
Ctxt.ForceServiceResultAsJSONObject,
{$ifdef LVCL}nil{$else}fBackgroundThread{$endif}) then
exit; // wrong request
finally
if optExecLockedPerInterface in fExecution[Ctxt.ServiceMethodIndex].Options then
LeaveCriticalSection(fInstanceLock);
end;
if Ctxt.Call.OutHead='' then begin // <>'' for TServiceCustomAnswer
Ctxt.ServiceResultEnd(WR,Inst.InstanceID);
Ctxt.Call.OutHead := JSON_CONTENT_TYPE_HEADER;
Ctxt.Call.OutStatus := HTML_SUCCESS; // <-----------------
end
else if (Ctxt.Call.OutStatus = 0) then // <-----------------
Ctxt.Call.OutStatus := HTML_SUCCESS; // <-----------------
WR.SetText(Ctxt.Call.OutBody);
// Ctxt.Call.OutStatus := HTML_SUCCESS; // <----------------- commented out
[…]
end;
Does this seem like a viable solution?
Last edited by avista (2014-06-20 06:51:00)
Offline
Yes, sounds fine.
I would like to review it before applying the patch.
Could you please add a feature request ticket so that I add this feature?
See http://synopse.info/fossil/tktnew
Offline
OK - forget the ticket.
I've just implemented it, pretty close to your patch.
See http://synopse.info/fossil/info/cc8721bad1
Finally, the new Status field could be overriden with a propert HTML code, if the default HTML_SUCCESS is not enough for your purpose.
Note that when consumed from Delphi clients, HTML_SUCCESS is expected to be returned by the server: you should customize Status field only for plain AJAX / web clients.
Thanks for the feedback and proposal!
Offline
Thanks, it is very much appreciated!
Offline