You are not logged in.
Hi there everyone,
I have been tasked with migrating an existing legacy mORMot 1 interface based REST server to mORMot 2. I have a function called SayHello that is called/tested using Postman, Insomnia etc like this: http://localhost:8088/api/service/v2/root/sayhello?params={\"db\":\"maindb\"}
This works in mORMot 1 but after migration to mORMot 2, I keep getting {"errorCode": 400, "errorText": "Invalid URI"} via TRestServerRoutingRest according to the logs.
I have combed through the forum for a solution and what I found seem to relate to method based services, for example https://synopse.info/forum/viewtopic.ph … 930#p40930.
This is how I start the interface services REST server,
procedure TServerDaemon.Start;
begin
Model := TOrmModel.Create([], 'api/service/v2'); // URI is on 'api/service/v2'
RestServer := TRestServerFullMemory.Create(Model, false);
// Define the service server side since service was previously registered in the RESTInterface unit
ServiceFactoryServer := TServiceFactoryServer(RestServer.ServiceDefine(TRestMethods, [IRoot], TServiceInstanceImplementation.sicClientDriven));
ServiceFactoryServer.SetOptions([], [optErrorOnMissingParam]);
HttpServer := TRestHttpServer.Create('8080', [RestServer], '+', HTTP_DEFAULT_MODE, 32, TSQLHttpServerSecurity.secSynShaAes);
end;
There services are consumed by web browsers. There is no Delphi/FPC client. I would really appreciate your help in the solving this problem because we would really like to try the new features of mORMot 2 in a production setting.
Thanks a million,
JD
Offline
Are you using the latest mORMot 2 version from today?
Then try to GET or POST on /api/service/v2/root/sayhello
It should trigger the IRoot.SayHello(const Params: variant) method.
Also note that secSynShaAes should not be defined, because it is unsafe. And it is not supported by web brothers.
It is much better to use HTTPS, with a proper certificate.
Offline
Hi there ab,
Thanks for the quick reply. I normally get mORMot 2 from GitHub https://github.com/synopse/mORMot2. I just download the zip file provided by the Code button and extract it to a local directory in my Lazarus installation. I just did that and I still got the same invalid URI result.
Is there any other version elsewhere?
Cheers,
JD
Offline
No, this is the last trunk.
Put a breakpoint in TRestServer.Uri and make a GET on /api/service/v2/root/sayhello.
If it does not reach there, try /api/service/v2/timestamp then /api/service/v2 and /api/service/v2/root
At least /api/service/v2/timestamp should always respond from the browser.
Offline
Put a breakpoint in TRestServer.Uri and make a GET on /api/service/v2/root/sayhello.
If it does not reach there, try /api/service/v2/timestamp then /api/service/v2 and /api/service/v2/rootAt least /api/service/v2/timestamp should always respond from the browser.
Hi there ab,
I did it and just as you said, /api/service/v2/timestamp works and returns a timestamp value.
However, the others did not work at all, and it still says {"errorCode": 400, "errorText": "Invalid URI"}
Stepping through the TRestServer.Uri procedure, I noticed that on the following conditional test on line 7627,
if (node = nil) or (ctxt.fNode = rnNone) then
the value of node was nil for all the other URIs I tested above except for the timestamp URI and hence the error below was generated
ctxt.Error('Invalid URI', HTTP_BADREQUEST) // root ok: error 400, not 404
Here is a link to the log file https://paste.ee/p/mgq9r
That is as far as I've gone at the moment. Any further help/suggestions will be most welcome.
Cheers,
JD
Last edited by JD (2024-08-18 16:11:57)
Offline
How is your IRoot client defined?
Why are you using sicClientDriven?
My guess is that sicClientDriven requires a session from the client side, so you can't make a simple "get" on its methods.
Try with sicShared for instance.
Offline
Hi there ab,
Thanks a million!!! It now works! Using sicShared instead of sicClientDriven was the difference.
I'm a little bewildered though because our old mORMot 1 based REST server in production uses sicClientDriven and it works fine.
Initially, the REST server was the backend for multiple FreePascal clients, but they were discontinued and browser/Java clients were introduced, BUT the REST server remained unchanged throughout the transition.
What is the difference between sicShared and sicClientDriven in mORMot 2 and why is sicShared better?
Thanks for finding the time to help me on a Sunday evening.
Cheers,
JD
Last edited by JD (2024-08-19 08:02:50)
Offline
The mORMot 1 doc still applies about execution modes.
https://synopse.info/files/html/Synopse … ml#TITL_92
In fact, sicClientDriven should be used only if you want to track the instance from the client side: one interface on the client side, one working class instance on the server side.
So it maintains a session number, and requires a Delphi/FPC client with the proper client-side logic.
mORMot 1 was buggy if no explicit session was created: it created one for each call.
mORMot 2 does what it is supposed to do: reject any sicClientDriven requests which do not have a proper client-driven instance pre-registration.
Offline
Thank you very much for the clarification, ab.
By the way, the interface is defined as follows
TRestMethods = class(TInjectableObjectRest, IRoot)
Is TInjectableObjectRest the best thing to use here or does mORMot 2 propose a better alternative?
Cheers,
JD
Last edited by JD (2024-08-19 10:49:50)
Offline