You are not logged in.
I did not remember changing anything about RootRedirectGet.
Just throwing this out there, it might have zero impact, but I noticed it while reading last month's commits: rsoAllowSingleServerNoRoot (this option was in fact not implemented at all in mORMot 2 !)
ITWT désolé
You are missing the object creation that will trigger an AV and use ObjectToJson, not JsonEncode.
function TUtilisateursService.GetUtilisateur(aID: TID): RawJSON;
var
obj: TOrmUtilisateurs;
begin
obj := TOrmUtilisateurs; // <- missing create
try
if not fClientDB.Orm.Retrieve(aID, obj) then
raise ERestException.Create('404 - Utilisateur non trouvé');
Result := ObjectToJson(obj);
finally
obj.Free;
end;
end;
ou
function TUtilisateursService.GetUtilisateur(aID: TID): RawJSON;
var
obj: TOrmUtilisateurs;
begin
obj := TOrmUtilisateurs.Create(fClientDB.Orm, aID);
try
if ID = 0 then
raise ERestException.Create('404 - Utilisateur non trouvé');
Result := ObjectToJson(obj);
finally
obj.Free;
end;
end;
read there: SAD1.18 5.2. Working with Objects
to check the command you show you could do it in InBeforeBody, you could validate specific upgrade in flags hsrConnectionUpgrade.
edit: what @ab just said
If it helps you find the way, on my side, I use TWebSocketProtocol.UpgradeBearerToken for that: read more there
FYI you can make code simpler with
with ServiceDefine(TAdmin, [IAdmin], sicPerSession, SERVICE_CONTRACT_NONE_EXPECTED) do
begin
ResultAsJSONObjectWithoutResult := True;
SetOptions([], [optErrorOnMissingParam])
end;
I’ve always felt that current large language models aren’t very friendly toward Object Pascal
don't be fooled ..
What data has GitHub Copilot been trained on?
GitHub Copilot is powered by generative AI models developed by GitHub, OpenAI, and Microsoft. It has been trained on natural language text and source code from publicly available sources, including code in public repositories on GitHub.
.. and it's not the only data source; You know.. personal privacy.. checkbox.. big-data, etc...
the mORMot framework is so BIG and complex that inputting a relatively small number of tokens rarely yields effective outputs.
The main issue, IMO, comes from when most datasets were built. The first public release of mormot v2 was around late 2020 (first commit in march 2020), but by then the models had already ingested mormot v1 source code. That’s why on gpt-3, gpt-4 (and even gpt-5!), you often get v1-based code in the answers - I'am quite sure you got the TSqlModel instead of TOrmModel things, etc. which is why the “big prompt” is actually useful.
Also, if you let your tools adapt to your own habits, you’ll naturally get better results. On my side, no matter what I ask, I always end up with a marmot somewhere in the answer
I mostly use cursor for frontend tasks, like building React dashboards or working with (syn)mustache templates (it actually works really well on Pascal codebases too). But I have to admit - warp terminal is a beast. I will try to make you a small demo if you’re interested.
To be honest, the real secret is to simply RTFM for each tool and configuring it properly, then taking the time to create a solid project structure (folder tree, rules, contextual prompts, etc) and calling the right model for a given task. The models to be used is now gpt-5 (truly impressive), claude-4-thinking and gemini-2.5-pro-thinking.
I'am not following ai trends closely but I'am quite sure claude-5 is in the pipe.
Do you mean that through mcp-delphi, the tokens input to Gemini or ChatGPT can be significantly reduced? I'm sorry, but I'm a bit confused about how this is achieved. Could you give us some hints?
No. At this moment, the mcp-delphi server only allows AI agents to use your IDE to compile your project (Delphi, Lazarus, or FPC directly) and get the output, nothing more. That said, if your coding tool supports "auto-mode", you can let the agents create, compile, and fix the project for you - while you’re cooking, for example I tried it with gpt-5, project built successfully and potatoes where not burnt lol.
Then I thought it could be useful to have a dedicated MCP server for working with mormot. It would definitely reduce the number of tokens consumed, since the agents would be able to query a well structured knowledge base for the relevant part of the framework instead of injecting a huge prompt. I also believe the agents would "think" better as their memory context wouldn’t be overloaded.
Cool, thanks for the contribution - I’ll ping you on the PR once I’ve compared it with the pushed changes
made a pull request too
Thanks! I’ll review it this weekend. Is it based on the latest mORMot update?
Thanks for sharing, @koraycayiroglu.
I’ve since refactored parts of the setup and will clean and push the changes to the repo. For example:
We now use ServiceRunningContext via a locally assigned PServiceRunningContext variable.
I addressed an oddity in the token refresh flow — previously it retrieved logonname and password from query strings. Instead, I now generate a token_refresh_uuid embedded in the token payload, and retrieve the logonname from the built-in jcIssuer. This allows validating the user by combining it with the sessionkey.
The goal is to send credentials only once to obtain a valid JWT, and never send them again.
I published a MCP server for delphi and lazarus/fpc; I am working on a special setup focused on mormot2. I must say from my tests with gemini - and now gpt-5 included - it's quite amazing. Token usage will be reduced a lot compared to "the-big-prompt".
You can find it there: https://github.com/flydev-fr/mcp-delphi
The way I learned to use Mormot was by conducting a global search for potential keywords, which was quite challenging.
I thought SAD 8.3[.6] (External database ORM internals) and api/mORMotDB.html might help clarifying.
at least I get some more doc to ingest.
Default "const" would pass it as two registers, not as a single register pointer.
Aw nasty. Thanks you ab
I still didn't found where it happen exactly - in DecodeUriParametersIntoJson, InBody is built correctly with an uuid string in a json array. The issue seem happening elsewhere and deeper in ExecuteJson(). I will continue tomorrow.
I could observe that it happen only when the parameter is defined as const (required with TServiceCustomAnswer as return type) and then found that a method like:
function Example(const uuid: TGUID): RawUtf8;
.. produces the same problem. If using var/out TGUID, result is ok.
I just tested with `curl http://localhost:9088/api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21` and I have the very same issue, result:
uuid is: 17868178-0000-0000-0000-000000000000
Then I have also compiled the server on ubuntu and same problem. FPC version on Ubuntu is 3.3.1. The lazarus project file is based on MVCServer.lpi with -Xm and compiled without optimization. I will test it with a simple and new project..
---
Edit:
I have created a new simple project on ubuntu and compiled, result is the same, the guid is wrong.
1) Yes, but maybe I was unclear earlier, I cross-compile for both Windows and Linux on my Windows machine (FPC 3.2.2). I must say that I have compiled it directly on Ubuntu two months ago and got the very same issue.
2) no unit windows. I traced it to objpash.inc, line 134.
The server is behind nginx. The GUID param received on Linux is not null, but incorrect.
I compiled for linux and windows with "clean up and build" before posting here. Test results:
Linux: uuid is: 40918D38-0000-0000-0000-000000000000
Windows: uuid is: 3C28EA56-37FE-4ABC-A0B7-508D8C634E21 (as expected)
- Logs Linux:
$ + AuthServer.TRestServerAuth(408199d0) URI GET api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21 in=0 B
$ call AuthServer.TRestServerAuth(408199d0) UserService.ReadTest len=40 ["3C28EA56-37FE-4ABC-A0B7-508D8C634E21"]
$ srvr RestJwtAuth.TRestRoutingREST_JWT(70f85803e000) Interface GET api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21=200 out=51 B in 555us
$ ret AuthServer.TRestServerAuth(408199d0) Interface len=51 uuid is: 40918D38-0000-0000-0000-000000000000
- Logs Windows:
+ AuthServer.TRestServerAuth(05ddad08) URI GET api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21 in=0 B
call AuthServer.TRestServerAuth(05ddad08) UserService.ReadTest len=40 ["3C28EA56-37FE-4ABC-A0B7-508D8C634E21"]
srvr RestJwtAuth.TRestRoutingREST_JWT(06389a18) Interface GET api/main/UserService.ReadTest?user_uuid=3C28EA56-37FE-4ABC-A0B7-508D8C634E21=200 out=51 B in 439us
ret AuthServer.TRestServerAuth(05ddad08) Interface len=51 uuid is green: 3C28EA56-37FE-4ABC-A0B7-508D8C634E21
I will test with curl on the linux server without nginx in about 15 minutes.
Again, just a small question about TGUID as I’m hitting a cross-platform snag with FPC 3.2.2 but with TGUID defined as param on SOA:
IUserService = interface(IInvokable)
['...']
function Read(const user_uuid: TGUID): TServiceCustomAnswer;
end;
- Win64 build (FPC 3.2.2): user_uuid arrives with the expected value.
- Linux x86-64 build (same sources & FPC version): user_uuid is always null.
Is this due to missing record RTTI for TGUID under FPC on Linux?
I can tackle the problem by passing it as RawUtf8, but I'am asking for my own knowledge.
thanks
Hi, because it's a string, it's appending a string item to a json array.
Use IDocDict to add an object:
LDocList.AppendDoc(DocDict(['text', 'test']));
or you can serialize directly:
LDocList.Json := '[{"text": "test"},{"text": "test2"}]'; // don't make sense: `DocList('[{"text": "test"}]');`
when the array (Len) is not empty, you can assign an object directly to it using:
LDocList.O[1] := DocDict(['text', 'test2 is now test3']);
@Alek, to force partial changes to be reloaded, apply theses modifications:
on mormot.rest.mvc.pas#L181 add:
FViewPath: RawUtf8;
and the public property:
property ViewPath: RawUtf8 read FViewPath write FViewPath;
on line mormot.rest.mvc.pas#L1245 add:
{$ifdef DEBUG}
fViewPartials.ViewPath := folder;
{$endif}
replace mormot.core.mustache.pas#L1317-L1332 with:
function TSynMustachePartials.GetPartial(
const PartialName: RawUTF8): TSynMustache;
var
i: PtrInt;
Temp: TSynMustache;
begin
if self=nil then begin
result := nil;
exit;
end;
i := fList.IndexOf(PartialName);
if i<0 then
result := nil
else
begin
// Partial files by default in mORMot are loaded just once and then cached which is very bad
// during debugging when files are changed and it requires constant restart of the application.
// With this change we're disabling cache in debugMode: -dDEBUG on fpc
Result := TSynMustache(fList.Objects[i]);
{$ifdef debug}
begin
Temp := TSynMustache.Parse(AnyTextFileToRawUTF8(UTF8ToString(MakePath([FViewPath, PartialName + '.partial'])), true));
if Temp.Template <> '' then
Result := Temp;
end;
{$endif debug}
end;
@ab, any chance you consider adding it or similar - or did we missed something?
---
Edit: I missed last post of @ab - watching for files changes and triggering FlushAnyCache() should be the right way to do it while developping. Anyway, the method presented here still make getting partial markup changes easier.
---
UPDATED: and I also don't quite understand the meaning of the variables.
I made a gist trying to explain it (should be correct), read there: https://gist.github.com/flydev-fr/e0f0a … c2ac78f2bc
Call FlushAnyCache when you change data in your model. If I am correct, on the blog sample, the default data is cleared and filled with new data again if empty on GetViewInfo(). The method is virtual so you can implement your own flush logic there.
... i think no one will make a server on mobile platform.
Sure — but on the other hand, I know a few friends in the IT sec field who would be stunned to carry a mobile phone running a dedicated app instead of walking around with an offline raspberry or any other pocket device.
I started working on it.
When I was doing my daily commit reading, I couldn't help but smile wide… and the image of @ab that popped into my head was ..
I can't reproduce it - it work as expected at least on fpc 3.2.2.
edit: ... and mormot 2.3.10775
@fatimaEzz, unit is "mormot.crypt.secure".
protip: consider using a specialized tool to perform recursive content searches within a specified folder (/mormot/src), eg. Agent Ransack (free).
hi @ab,
I'd like to propose the addition of a helper function in `mormot.core.rtti.pas` to enhance support for parsing scoped CSV values into enum sets.
About use case, in JWT-based APIs, I often use enum sets encoded as scoped strings such as: `users:create,users:read,system:logs`
These values are not directly mappable using `GetSetCsvValue()` due to their prefixed format (I might missed an existing gem!).
I wrote a helper named `GetSetCsvValueTrimmed()` which uses `TrimOneChar()` to remove the scoped prefix before matching against enumeration names (maybe another internal function would be more appropriate):
/// Parse a delimited list of scoped identifiers into a set, returned as a 64-bit bitmask
// - each entry in the CSV should follow a scoped naming pattern, e.g. 'users:create'
// - the prefix separator (scopeChar) is customizable and defaults to ':' if not specified
// - this function is similar to GetSetCsvValue(), but will remove the scope prefix
// from each identifier before matching it against the enumeration names
// - returns 0 on parsing failure, or if none of the values map to known enum items
// - expects aTypeInfo to point to a set of enumerations with matching names
function GetSetCsvValueTrimmed(aTypeInfo: PRttiInfo; Csv: PUtf8Char; scopeChar: AnsiChar = ':'): QWord;
function GetSetCsvValueTrimmed(aTypeInfo: PRttiInfo; Csv: PUtf8Char; scopeChar: AnsiChar): QWord;
var
tmp: RawUtf8;
begin
result := 0;
if (Csv = nil) or (Csv^ = #0) or (aTypeInfo = nil) then
exit;
// remove scopes like 'users:' or 'system:' prefixes from each value
tmp := TrimOneChar(Csv, scopeChar);
result := GetSetCsvValue(aTypeInfo, pointer(tmp));
end;
If it makes sense, I also wrote unit tests to validate typical JWT-like scope strings.
type
TEnumPetStorePerm = (
epsPermNone, epsStoreRead, epsStoreWrite);
TEnumPetStorePermSet = set of TEnumPetStorePerm;
checkEqual(GetSetCsvValueTrimmed(TypeInfo(TEnumPetStorePermSet), 'store:read,store:write'), 6, 'TEnumPetStorePerm');
// ...
Thanks!
I published a gist with a working example (mormot2), assuming a TAuthUser is on external db, feel free to change the table name with one of your..
TRestClientDB use an hidden TRestServerDB; you could map to an external db for example this should work:
Props := TSQLDBZEOSConnectionProperties.Create(...);
Props.ThreadSafeConnection.Connect;
OrmMapExternal(aORMSQLModel, [TYourOrmMapped], Props);
ORMDB:= TRestClientDB.Create(aORMSQLModel, nil, ':memory:', TRestServerDB, False, StringToUtf8(aPassword));
TRestServerDB(ORMDB.Server).Server.CreateMissingTables(0, [itoNoAutoCreateUsers]);
I dont really get what you are asking specifically, but did you took a look at /ex/extdb-bench or mongodb & techempower samples? also read test.orm.extdb.pas from test folder.
Basically to get a TRestServerDB virtually working with MariaDB, there is a generic connection definition:
// 1. Define your external SQL connection
Props := TSQLDBZEOSConnectionProperties.Create(
FormatUtf8('zdbc:mysql://127.0.0.1:%/%?username=%;password=%',
DB_PORT, DB_SOURCE, DB_USERNAME, DB_PASSWORD]),
'aSqlite3.db', DB_USERNAME, DB_PASSWORD);
Props.ThreadSafeConnection.Connect;
// 2. Define your model and ORM mapping
Model := TOrmModel.Create([TOrmSomething]);
OrmMapExternal(Model, [TOrmSomething], Props);
// 3. Create the REST server, mapped to the external DB
Server := TRestServerDB.Create(Model);
Server.Server.CreateMissingTables;
My pleasure
I forgot to talk about the tool. To get the mopenapi tool, just compile it from there src/tools/mopenapi (blog post) and then you will be able to get a JsonClient and DTOs defintions in a second and ready to work with your API, then just throw the DTOs code on Gemini if you want them on your interfaces or whatever.
To get the JSON file from YAML, just use any YAML <> JSON converter - I will send a PR to handle YAML on mopenapi tool directly if ab accept it
I posted a small readme there, sorry I had to do it fast as I am at work, feel free to ask.
Hi @zen, yes I can - let me create a repo for that.
did you include the implementation parts of all unit files? (I always thought AI finds that part useless.)
Yes because of two things. The first is that the frameworks is complex and I know models are subject to hallucinations while working with mormot; For example you can get GPT working on v2 only after corrections and sending to the models samples.
The second, I had the sentiment that Gemini had a lot of power, and with 1 million of tokens context (like GPT 4.1 now) I tested to throw the full source code. And it worked like a charm
And as the tests are written by @ab and show the right way of implementing things, then I through it was the best idea to pack the tests. FYI, packing the WHOLE framework don't work as you will get too much tokens, like 2 or 3 millions - so you must choose the best parts based on what you are trying to achieve.
Hi everyone,
I've published a small JavaScript module to NPM registry called mormot2-timelog.
This module provides utility functions to convert mORMot2's TTimeLog (Int64) values to and from standard JavaScript Date objects and ISO 8601 strings. This can be useful when working with mORMot2 backends and JavaScript frontends, eg. to show TCreateTime and TModTime as human readable date.
You can find it here: https://www.npmjs.com/package/mormot2-timelog
The source code and usage examples are on GitHub: flydev-fr/mormot2-timelog
Hope this is helpful to the community
Lol
Perhaps worth generating a mORMot 2 pdf, to meet the AI beast.
yes! I did a try last month with Gemini, to generate a full project based on mormot2. I packed almost the whole mormot source and test folder with repomix, added some custom corrections I was used to and thrown a prompt of 900,000 tokens to Gemini. It has ended with a project of multiple REST servers, all the interfaces and services implementations and an openapi definition file.
I then could generate the whole JsonClient and DTOs with mormot tool. I just had to make some minors corrections - impressed as f**.
Yes, I would appreciate that.
I forgot to tell that if you want to play with it, I ported the project on mORMot v2 some months ago and I can publish it.
I had this issue and I had to write my own TRestServerAuthentication* handler and overriding `SessionCreate()`, `RetrieveSession()` and `Auth()` as because HandleAuthentication is set at RestServer level, session logic is expected.
I found the thread that explain what I said, there: /forum/viewtopic.php?pid=30095#p30095
You will find a nice example (v1) from @Chris75018.
I published a small example on github: flydev-fr/mormot2-jsonclient
and small comments project1.lpr#L29-L38
look how the client is used in `petstore.client` (generated by mopenapi)
Check request headers:
Hi @ab I had read this thread two times but missed this message! thanks
Hi there,
A small question, is TGuid supported as published property on Orm class? I have no issue with delphi but on FPC I get "Error: This kind of property cannot be published".
Just use `SetBearer`, you can of course just set header manually.
I am a bit late, for question #1 I like to give as reference this awesome post:
refresh-tokens-what-are-they-and-when-to-use-them on auth0.com blog.
Well explained and make things crystal clear.
Also, it will be easier to find it when searching on forum
Yes, you can implement a JWT-based authentication endpoint in your server. Could either be provided directly by your server (via a secret key) or integrated with an existing identity provider like Hanko or Auth0.
hi, hard to say without more details. Start by enabling log with LOG_VERBOSE level then check logs once it happen again.
v.a := _Arr(['2']);
//
_safe(v)^.Values[0] := _Arr(['3']);
_safe(v.a)^.Values[0] := '4';
//
DocDictFrom(v).Update('a', _Arr(['5']));
with DocListFrom(v.a) do
U[0] := '6';
{"a":["2"],"b":"2"}
{"a":["3"],"b":"2"}
{"a":["4"],"b":"2"}
{"a":["5"],"b":"2"}
{"a":["6"],"b":"2"}
@youssef, remove route and add the correct one with https scheme. Your issue seem to be the route is already registered for http.
read this:
link to documentation + windows tool:
https://synopse.info/forum/viewtopic.ph … 368#p42368
I think @zen010101 is suggesting you this post:
https://synopse.info/forum/viewtopic.ph … 664#p27664
A README file would be great too, to explain what each sample is about
Sure, thanks.
I like the idea @mpv
@ab is there any rules to follow before making PRs about pushing some samples dedicated for mormot2?
I finished to write a vanilla js lib which support mormot custom auth scheme that will be available on github and i would like to provide samples projects about it.
I have other projects as well, like client/server websockets, an mvc dashboard, etc. I thought they might be useful to other developers.
... because I will speak at two great places:
- the danish Delphi user group - see https://blog.synopse.info/?post/2024/10 … of-Denmark
- the EKON 28 conferences - see https://entwickler-konferenz.de/speaker/arnaud-bouchez/
I’m hoping to be there at the next EKON you’ll be participating in to learn, listen to your insights, and finally ask a question I’ve been wanting to ask for over five years! Enjoy the sessions
@cadnan, see gpt o1 suggestions:
Hi, I’ve just published a project that you might want to check out. Its based of a larger project I’m working on (inspired by Rails ActionCable and designed to work with mormot MVC). I’ve stripped the code a bit, so you’ll get a WebSockets server and some event handling. I’ve also included a JS client for chat functionality.
I’ll try to create a lighter sample this weekend based on the example you linked from Embarcadero.
You will need NPM or yarn installed to run the js project. I can build it to be ran without js tooling, just let me know. Anyway, you can connect with any websockets client on `ws:127.0.0.1:8082/cable` endpoint.
Files of interest:
- chat_channel.pas
- token/token.pas
- http-server/ws_server.pas
Do not pay attention to InitMVCApp and other mvc things.. hope it help
求大神指点一下啊
Sure, but please do some effort to post in english [3]..
meanwhile a better answer, read: https://www.synopse.info/forum/viewtopic.php?pid=42232
and https://www.google.com/search?q=site%3A … m+Error+87