You are not logged in.
Hi,
The main point I'd like to make is that there is no documentation or guide for learning the basics of this framework.
There are only references from the website to GitHub and back again. In the end, you can only look at the sample programs!
It's very frustrating that there is no explanation of how to work with this framework from the ground up.
Offline
Hi, I can understand your point of view but some statements are false like about the documentation, at contrario the doc is quite gigantic and can be complex on the first read - but once you get a bit familiar with the framework structure and conventions, the doc turn easy to understand and will became your handbook, and it's still also true if we take into account that the current full documentation is about the version 1.
From the ground up, I can only suggest to read the whole introduction which include chapter 1, 2 and 3 - then play without getting into details with the samples, I mean compile, test and then read the code, then going from code to the documentation to make some corelation, also, the whole source code contain detailled comments.
You can find also Thomas (tbo)'s tutorials (read the readme linked on github), and to be honest, the full samples from the v1 are still useful.
Some links:
- doc v1 (v2 is a wip)
- Thomas tutorials (you will find write up, translatable, on delphipraxis)
- Stephan Bester's intros on Medium
- Again, some tutorials based on the v1, but still applies!
- A lot of samples there
The learning curve is rude, but definitely worth it.
Offline
Yes, the links in the first paragraph of the README in the repository do apply.
Offline
Thanks for your guidance, friends.
I know enough to build a simple server and use a websocket with it.
I'm looking for the basic concepts and principles to have a good understanding of its structure in order to create a large system.
I've already written five large APIs with Horse. Recently, a friend of mine mentioned that mormot v2 has changed a lot. It is very fast. That's why I decided to write the new API with mormot. But I have a superficial understanding of it. I would like to know how to get the most out of it.
Offline
Just keep in mind what's already said as you will need these references, then read New Async HTTP/WebSocket Server blog post to get a better overview and then run/study the code of the program used for the techempower benchmark which is IMO the best starting point as it show almost all of what you will need for your endpoints, without complexity.
Just grab the project, uncomment USE_SQLITE3, compile and test urls with Postman, browser or favorite tool.
Offline
Horse is nice, for a basic server-side API.
It claims to be fast: I don't see why it should be especially fast in respect to alternatives, because it is based on other web servers (it does not have its own web server).
Perhaps it is faster than Datasnap, but it is not difficult.
It could be a good idea to include Horse in the TFB benchmark, for instance, and compare with mORMot (and its own async web server) which ended in rank #12 against the most tuned proof of concepts of other languages:
https://www.techempower.com/benchmarks/ … =composite
To be fair, a REST API is just one brick of server-side process.
For a large API with mORMot, the easiest and most maintainable is to use interface-based-services, with several interfaces, and dedicated methods.
Using interfaces is IMHO the cleanest way to define an API, and follow strong coding principles like SOLID.
Over websockets, you can have real time response from the clients to the server, with minimal coding.
Another advantage is to have ready-to-use Delphi/FPC clients using RTTI, or abilities to generate client code or documentation.
And it is still a regular API using standard JSON + HTTP(S) to communicate.
I understand your scepticism against mORMot size and learn curve.
It is closed to WCF interfaces defined in strong-typed C#, than JavaScript-like frameworks.
We still plan to make some high-level wrapper about mORMot classes, to get quickly started.
Offline
Thank you for your responses, friends.
I understand that there are three ways to work with mORMot:
1 - The REST ORM
2 - Methods-based services
3 - Interface-based services
I also didn't understand how to create multiple routes for my API. What I did was look for the route name in the URL in the OnRequest event and execute a function.
I also tried to use the route and router properties in the following way, but it didn't work:
fHttpServer.Rout.Get('Ping',Ping);
fHttpServer.Router.Get('Ping',Ping);
Last edited by Kabiri (2024-06-27 08:07:04)
Offline
As I wrote, I would advice using Interface-based services for any project with a growing number of endpoints.
Then you can make some routing in front of it, using built-in URI redirection from the outer route to the interface-based-service standard route, as generated by the RTTI.
https://blog.synopse.info/?post/2022/12 … -Christmas
Look at "Internal URI rewrite" in this blog article.
You can just set a RawUtf8 destination URI instead of a method callback.
Offline
Based on what I have learned, I wanted to create an interface-based server.
I do not want to use ORM on my server. That's why I did not create a class for orm and data.
The program stops with an error and I don't understand why.
---I have removed the code to comply with the rules.
Last edited by Kabiri (2024-06-30 17:53:12)
Offline
Hello,
1) Please follow the forum rules and don't put code in the messages directly.
2) You are using TServerRest which is NOT to be used as such: this is an abstract class.
Use TRestServerFullMemory instead, as documented:
// Update() Delete() methods - so if you want a REST server with no ORM
// (e.g. for a pure SOA server), use (or inherit) TRestServerFullMemory
Offline
Thank you.
I have created a new record for the output, but the JSON output contains both the input record and the record I defined for the output. What can I do to prevent the input from being sent in the output?
Also, how can I test this with Postman?
I tried several URLs in my Postman request, but the inputs are not being received.
get : http://127.0.0.1:8080/api/Calculator.Add/?Data={N1:1,N2:2}
post : http://127.0.0.1:8080/api/Calculator.Add
body-raw : {Data={"N1":1,"N2":2}}
Offline
Read the mORMOt 1 documentation about SOA parameters.
https://synopse.info/files/html/Synopse … #TITLE_405
TL&WR: none/const = input; var = input and output; out = output
And you need to supply some real JSON: use Data: and not Data= for values.
Offline
Thank you. I fully understood how to use the interface without using orm.
I have a problem with the client. If I don't understand, I will ask.
Offline
I've looked through the v1 documentation as much as I can, but I'm still not sure how to connect to the TRestServerFullMemory server for communication on the client side when I'm not using a model and orm.
I used TRestHttpClient and set the model parameter to nil. But I get an accessviolation error in the ServiceDefine instruction.
Offline
You TRestServerFullMemory is for the server side. As its name states.
On client, use TRestHttpClientSocket and set a model with no TOrm class, but the same root value ('api').
Take a look at the mORMot 2 samples, you would find all that you need for this.
Offline
I reviewed the mormot2 examples. In the examples, everyone uses the model.
Offline
I reviewed the mormot2 examples. In the examples, everyone uses the model.
Why is this a problem?
With best regards
Thomas
Offline
Why is this a problem?
With best regards
Thomas
That's not the problem.The problem is how to do it.
APIs can generate different types of outputs.
For example:
A method that simply returns a number as the API version.
A simple method (like ping) that returns a simple value (for testing connectivity).
Up to complex methods that return a record or records from a database.
Or even files or streams.
Therefore, an API needs to be able to access all types of methods.
Last edited by Kabiri (2024-07-03 21:48:23)
Offline
I reviewed the mormot2 examples. In the examples, everyone uses the model.
Orm model can have no objects;
TOrmModel.create([ ], arootName)
Offline
Don't be afraid my friend, Let me share with you my real life experience with mORMot 1 (even before Stephan Bester has written his excellent blog posts - not complete BTW, but it's still excellent), I have had success with mORMot 1 for several projects:
- I started with the examples.
- From time to time I encountered various questions/issues and all of them were addressed by one of the following:
- Check the documentation - you don't have to go through it in one time because it's HUGE, just find the info you need.
- Ask question here, ab the developer and other users were supper helpful and active.
- Submit issue and ab usually solve the issue in less a day or several days depending on the severity.
- And most of the time, check the source code and you'll get your answer.
One might have a steep learning curve with mORMot, and one might don't like the coding style , but it's DEFINITELY worth it because it's so feature-rich, stable, so fast and so fully-documented (the last point applies to v1 only, thus far, but I believe ab will fix it)! And the developer ab is so passionated and reliable, and the forum users are so active and helpful!
Last edited by edwinsn (2024-07-04 09:28:31)
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
Orm model can have no objects;
I understand. So in any case, the model must be created, but the model can be empty and not contain any objects.
Thanks
Offline
Thanks @edwinsn
I am determined to learn mormot2. I can use it with the help of examples, but I wanted to understand how it works. I have a lot of questions on my mind and I hope to find the answers soon.
It would be great if this forum had a "thanks" button for posts.
Offline
Thanks @edwinsn
but I wanted to understand how it works.
There are different parts in the framework - ORM, web service and so on.
Take ORM for an example, if you know how published properties work in Delphi, how JSON works, know well enough about SQLite (including basic db concepts and virtual tables in SQLite), and so on, you can find out how it works.
Actually I know very little about the framework - there are a bunch of modules that I've not used yet. That being said, give the fact that the v2 version is lacking, I'd suggest you learn from v1, I believe everything is there for you to understand it - the full set of examples, the documentation and the source code.
I believe V2 is very similar to v1 in terms of the concepts and architecture, except that the code organization, the class names and some of the implementation have changed. Moreover, with a bunch of new features added - off the top of my head, I know there is a new quickjs-based engine, LDAP, X.509, OpenSSL 3.x, and so on - BTW, I think ab should include a "What's new in mORMot 2 section" in the github home page
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
I am determined to learn mormot2
Definitely worth the effort - it's an excellent framework. I'd disagree with Edwin though - I'd concentrate on v2 and then back-reference to v1 when required. For v1 Stephan Bester's tutorials are very useful, as is https://tamingthemormot.wordpress.com/.
For more in-depth examples using v2 those by Thomas (tbo - mentioned above by flydev) are excellent.
Cheers, Bob
Offline
Thanks @ab
Thanks @edwinsn
Thanks @rdevine
I think I'll be busy with this for a few days.
The question that's on my mind is whether it's possible to have multiple ORM models, multiple JSON outputs from the database, and non-model methods in a single API.
Offline
I've been using Mormot for a long time and it was really difficult at first.
If I can give one piece of advice, don't mix the ORM layer with the API layer.
Create ORM classes just to interact with the database.
Create another layer of classes (DTO) for your api or business rules...
With your DTO you can return whatever you want in your api without any relation to ORM, making it much cleaner.
Offline
Non-model methods in the API is indeed a clean way to go.
You can definitively do this. This is even the preferred way of using mORMot on production.
Use interface-based services, each implementing class instance with its own internal ORM model, i.e. its own TRestServerDB.
The idea is that if you use TRestServerDB locally on the server side, and don't publish it over HTTP, it won't be available but for the API itself.
So it is more a "TRestDB" than "TRestServerDB", to be precise.
Offline
When you told:
Create ORM classes just to interact with the database.
Create another layer of classes (DTO) for your api or business rules...
Means that i have to read the objects to TOrmObjects and manually transport the data to the DTO records?
sample:
In someplace of my apy i need get a baby then a call the repository. with the repository pattern I can isolate the orm of all my application (Clean Code)
procedure TBabyRepository.GetBaby(pID: Int64; var pDTOBaby: TDTOBaby);
var
Baby: TSQLBaby; // store a record
begin
Baby := TSQLBaby.Create;
try
TRestDB.Retrieve(pID, Baby);
// transpose to DTO, TRestServerFullMemory can return to client
pDTOBaby.ID := Baby.Id;
pDTOBaby.Name := Baby.Name;
pDTOBaby.Address := Baby.Address;
pDTOBaby.BirthDate := Baby.BirthDate;
pDTOBaby.Sex := Baby.Sex;
finally
Baby.Free;
end;
end;
this translate can be very slow approach depending!
I can do this of other way?
Last edited by mrbar2000 (2024-07-05 20:45:01)
Offline
If the field names do match, you can just fill the TBaby record from JSON, directly from the DB, with no transient TOrmBaby.
What Orm´s Method I can use for this?
My TDTOBaby is a packet record! I just see ORM.RetriveXXX(passing TORMClass)
Can you show a simple sample?
Offline
I've been using Mormot for a long time and it was really difficult at first.
If I can give one piece of advice, don't mix the ORM layer with the API layer.
Create ORM classes just to interact with the database.
Create another layer of classes (DTO) for your api or business rules...
With your DTO you can return whatever you want in your api without any relation to ORM, making it much cleaner.
Thank you for your explanation.
I generally prefer to keep the ORM and API layers separate. I'm not sure if this would cause a performance decrease.
I've been busy with other things for a while, but now I'm back to learning about Mormot. I want to create methods both with and without Models on a single server, and connect to it using a client.
I hope this isn't too difficult and I'm not bothering anyone.
Offline
I'm not sure I understand correctly.
Do you mean I should write an application server on a server and have an API connect to it as a client, retrieve database information, and then act as a server itself to send the data to the client (user side)?
Offline
No, all the logic on the server side.
But without publishing the database via ORM on the client side.
But publishing the data as high-level API methods, without any ORM, so without any TOrmModel - leaving [] for the tables list.
Offline
Thank you. I will try it
Offline
@ab
I downloaded the new version of mormot2 yesterday.
In the mormot.core.base unit at line 36, the unit variants should be changed to system.variants.
Because it's giving a Circular unit reference to 'variants' error.
(Delphi 12.1)
Last edited by Kabiri (2024-08-13 13:52:22)
Offline
There is something wrong with your settings in the IDE, or of your project.
It seems to be a Delphi IDE bug, when importing the project.
Offline
In the unit 'mormot.core.variants', the unit 'mormot.core.base' is called,
which in turn calls 'variants'. However, the IDE mistakenly identifies it as 'mormot.core.variants'.
While this is indeed an IDE error (Or an unintentional setting in the IDE) , the easiest way to prevent this is to use 'system.variants' instead.
Last edited by Kabiri (2024-08-13 17:20:16)
Offline
Well, that's right. I hadn't thought about the FP.
Offline
I put a comment in the error place as reference.
https://github.com/synopse/mORMot2/commit/0998d945
Because this Delphi import "smart feature" is really confusing.
You are not the first to have been caught.
And won't be the last
Offline
This is a big challenge in the beginning. I had the same problem. First, I tried to work on the documentation with Json and how to work with it in mormot using docvariant and doclist. Then I went back to the examples and was able to modify it to create a very basic web service. Then I tried to understand the interface base service and method base service . And finally I worked a little with swagger.
Considering that in my existing database, the primary keys are narural key and compiste. I can't use orm. Because in Orm there must be a primary key for each table. So, I leave this section aside and use the functions that take the model and store it in the database by SQL.
The next step is how to call and share the interface for the client program. The power of mormot shows itself here. And how beautifully this work is implemented.
I'm still at the beginning of the journey, but I learned a lot within a month and I try to learn more every day.
I agree that it is much more difficult to start working with mormot than other frameworks.
It is natural that piloting a plane is more difficult than driving a car. But there are many unique possibilities here. Thanks to AB
Last edited by anouri (2024-08-14 09:05:58)
Offline
In the examples, I only saw connections to SQLite. What should I do for MSSQLServer?
Which units should I add?
Previously, when accessing the database,
I created a connection and then closed it after retrieving the data. (In the events related to creating and destroying the class) And apparently here, when the server is running, the connection is created and remains open until the end of the server.
Offline
this is my code to connect to mysql database. There are 2 service, invoice and inventory.
procedure TfrmMain.btnStartClick(Sender: TObject);
begin
StartServer('zdbc:mysql://localhost:3306/mysqldb?username=user;password=mypassword');
end;procedure TfrmMain.StartServer( aDbURI : RawUTF8 );
begin
LogFamily := SQLite3Log.Family;
LogFamily.Level := LOG_VERBOSE;
LogFamily.PerThreadLog := ptIdentifiedInOnFile;MyModel := CreatePassakModel;
aDbConnection := TSQLDBZEOSConnectionProperties.Create( aDbURI, '', '', '' );
aPassakServer := TRestServerFullMemory.Create(MyModel);
InvoiceService := TInvoiceService.Create(aDbConnection);
aPassakServer.ServiceRegister(InvoiceService, [TypeInfo(IInvoiceService)],'1');InventoryService := TInventoryService.Create(aDbConnection);
aPassakServer.ServiceRegister(InventoryService, [TypeInfo(IInventoryService)],'2');aPassakServer.ServiceMethodRegister('reports', InvoiceService.testCallBack);
AddToServerWrapperMethod(aPassakServer,['templates','templates']);
aHTTPServer := TSQLHttpServer.Create( HttpPort, [aPassakServer], '+', HTTP_DEFAULT_MODE);
aHttpServer.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries
memLog.Lines.Add('Background server is running.'#10);
memLog.Lines.Add('Cross-Platform wrappers are available at ' + HttpPort + '/' + HttpRoot );
end;
Offline
ok
As you can see in the code above, I pass the dbconnection to the InvoiceService constructor. I inject connection by constructor to service, and I hold connection in fConnection defined inside service. I hope it is the right approach.
I am concerned about one thing. Is a connection shared between different threads created by mormot for other services or operations? Doesn't it cause a problem in Mormot being multi-thread?
Last edited by anouri (2024-08-15 08:23:48)
Offline
Yes it is right approach. Just note, TSQL*ConnectionProperties is connection pool, not real db connection! Real db connection is TSQL*ConnectionProperties.ThreadSafeConnection and is created for your running thread. This connection is keep open and reuse for every call in same thread, because db connect is time expensive. I you really need to close thread connection you can call TSQL*ConnectionProperties.EndCurrentThread at the end of your interface/method.
Last edited by ttomas (2024-08-15 09:22:25)
Offline
thanks. but yo write "TSQL*ConnectionProperties is connection pool, not real db connection! Real db connection is TSQL*ConnectionProperties"
it is same!
TSQL*ConnectionProperties = TSQL*ConnectionProperties
Offline
As you can see in the code above, I pass the dbconnection to the InvoiceService constructor.
You must keep in mind that with the method you used to register the services, they are always sicShared. This is unimportant in a simple example, but you must take it into account for a server. But it is not necessary and with a little preparation you can implement it as shown in some examples.
Define your RestServer as follows:
type
TMainRestServer = class(TRestServerFullMemory)
strict private
FConnectionPool: TSqlDBOdbcConnectionProperties;
public
property ConnectionPool: TSqlDBOdbcConnectionProperties
read FConnectionPool;
CustomService as follows:
type
ICustomService = interface(IInvokable)
function GetConnection(out pmoConnection: TSqlDBConnection): Boolean;
end;
type
TCustomServiceObject = class(TInjectableObjectRest, ICustomService)
protected
function GetConnection(out pmoConnection: TSqlDBConnection): Boolean;
function TCustomServiceObject.GetConnection(out pmoConnection: TSqlDBConnection): Boolean;
begin
Result := False;
if TMainRestServer(Server).ConnectionPool <> Nil then
begin
pmoConnection := TMainRestServer(Server).ConnectionPool.ThreadSafeConnection;
Result := (pmoConnection <> Nil);
end;
end;
And use it in your services as follows:
var
json: RawUtf8;
dbConn: TSqlDBConnection;
dbStmt: ISqlDBStatement;
begin
if GetConnection(dbConn) then
begin
dbStmt := dbConn.NewStatementPrepared(...);
dbStmt.ExecutePreparedAndFetchAllAsJson(False, json);
With best regards
Thomas
Offline