#1 mORMot 2 » Documentation using systematic framework https://diataxis.fr » 2023-01-10 11:29:56

sevo
Replies: 1

Salut Arnaud,

just for your information - maybe the approach from https://diataxis.fr is of use for the new documentation.

Thank you for your great work!

#2 Re: mORMot 1 » High CPU-Load on Idle, ConsoleWaitForEnterKey (Windows Server 2019) » 2021-01-12 11:25:06

Thanks Thomas for your hint!

I successfully used your approach with mORMotService.TSynDaemon - High CPU-Load is gone.
But i had to use ConsoleWaitForEnterKey() instead of readln() in procedure TSynDaemon.CommandLine, else the mainthread was blocked and we currently use some Timers and Services running in Mainthread.

#3 mORMot 1 » High CPU-Load on Idle, ConsoleWaitForEnterKey (Windows Server 2019) » 2020-12-11 10:19:39

sevo
Replies: 4

Hi,

on Windows Server 2019 my console-application has constant 25% CPU load, conhost.exe another 25%.
On Windows 7, everything is just fine (< 1% during idle).

I'm using the function ConsoleWaitForEnterKey.

Can you give me a hint?

Thanks in advance!

#4 mORMot 1 » Disable Quickedit Mode in the command-line Windows 10 / Server 2019 » 2020-05-15 14:19:47

sevo
Replies: 3

Hi Folks,

you have to disable the QuickEdit Mode in the command-line on Windows 10 / Windows Server 2019.
Else your application hangs, waiting for key-input, as soon as you click inside the window.

Solution: https://stackoverflow.com/questions/338 … windows-10

Regards,

sevo

#5 Re: mORMot 1 » Template for generating Swagger-UI-JSON » 2019-07-09 10:23:11

Edtech wrote:

If I understand correctly, using TServiceCustomAnswer, I have to write my own wrapper to correctly generate the data to swagger?

As the typeinfo of TServiceCustomAnswer is missing in the /wrapper/context, the response model can not be generated.
Unfortunately, even aliasing the type, e.g. TMyServiceCustomAnswer = TServiceCustomAnswer, did not work. The type in wrapper/context gets resolved to TServiceCustomAnswer -> again no typeinfo.

The only way for now to document the response for TServiceCustomAnswer is to write a comment (/// + text/html) above the interface function definition.

#6 Re: mORMot 1 » Template for generating Swagger-UI-JSON » 2019-07-05 06:34:33

AFAIK if you use mormot interface services, only calls via POST or GET are supported.
See https://synopse.info/files/html/Synopse … #TITLE_454

If you want to e.g. call via DELETE, you have to use method-based services - these are currently not supported by the swagger-template.

#7 Re: mORMot 1 » Template for generating Swagger-UI-JSON » 2019-03-01 07:50:28

@ab it would be nice to have in the server-context
- a "fieldDescription" per record field
- the response-format, eg. ResultAsJSONObjectWithoutResult, ResultAsJSONObject, Default, XML... to generate the according response-schema for swagger.

#8 Re: mORMot 1 » Template for generating Swagger-UI-JSON » 2019-03-01 07:40:05

Hi Esteban,

i can not confirm. In my case, all the descriptions are in the servercontext and also in the genereated swagger-json.
I think the description of the record / enum has to be in the same unit as the interface definition of the service.

Here another small update for serviceDescription:

...
"tags": [
	  {{#soa}} {{#services}}
		{
			"name": "{{uri}}",
			"description": {{jsonQuote serviceDescription}}  //<-- was "Everything about {{uri}}"
		} {{^-last}},{{/-last}} 
...

Regards,

sevo

#9 Re: mORMot 1 » Template for generating Swagger-UI-JSON » 2019-02-28 10:12:48

Hi all,

i have some additions, marked as "//<-- .."

...
"info": {
        "description": "Generiert durch mORMot {{mORMotVersion}} am {{time}}",
        "title": "Services von {{protocol}}://{{host}}:{{port}}/{{root}}"                   //<-- add Server details
...
"definitions": {
      {{! Records }}
      {{#records}}
        "{{name}}": { 
            "type": "object",
            "description": {{jsonQuote recordDescription}},                                                       //<-- add record description 
            "properties": {
...
{{#enumerates}} 
       "{{name}}": {
          "type": "integer",                                                                                        //<-- change type to integer (enum-index)
          "enum": [
          {{#values}}
               {{-index0}} {{^-last}},{{/-last}}                                                         //<-- use enum-index for enum-parameters
               {{/values}}
          ],
          "description":                                                                                                                                      //<-- add enum-descrtiption
             "{{enumDescription}}\n\n{{#values}}\n{{-index0}} = {{.}}{{^-last}},{{/-last}}\n{{/values}}",    //<-- add enum-descrtiption

          "required": true
        },
{{/enumerates}}
...

Edit: correct use of jsonQuote, was double-quoted

#10 Re: mORMot 1 » Custom Header in Crossplatform System.Net.HttpClient not sent » 2018-08-29 11:37:32

Thx for your reply!

Instead of HTTP-Headers I should use URL-Parameters.

I managed to do so using UrlEncode:

Call.InBody := //binary data from picture
Call.Url := Client.Model.Root + '/' + 'UploadPicture' + UrlEncode(['Param', 123, 'Context', 456]);
Call.Verb := 'POST';
Client.URI(Call);

Why are in UrlEncode only a-zA-Z as parameter names allowed?

According to https://www.ietf.org/rfc/rfc3986.txt the query can consist of *( pchar / "/" / "?" )
Where pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
and unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"

Edit: typo

#11 mORMot 1 » Custom Header in Crossplatform System.Net.HttpClient not sent » 2018-08-29 08:18:36

sevo
Replies: 2

Hi Folks,

i want to send binary data (a Picture) with additional HTTP-Header-Data from an Android-App using Firemonkey (FMX) to a method-based service.
But in unit SynCrossPlatformSpecific.pas procedure THttpClientHttpConnectionClass.URI(var Call: TSQLRestURIParams, ...) the HTTP-Headers in parameter Call.InHead are not used/sent.

IMHO the Call.InHead must be filled into a TNetHeader array and passed to the THttpClient.Post/.Put/.. functions.

Here is a working - but naive and memory-leaking function:

procedure TextToNetHeaders(Text : String; var Headers : TNetHeaders);
var
  Pairs : Integer;
  sl : TStringList;
  i, Sep : Integer;
begin
  sl := TStringList.Create;
  try
    sl.Text := Text;
    SetLength(Headers, sl.Count);
    for i := 0 to sl.Count - 1 do begin
      Sep := Pos(':', sl[i]);
      Headers[i] := TNetHeader.Create(Trim(Copy(sl[i], 1, Sep - 1)),
                                      trim(Copy(sl[i], Sep + 1, MAXINT)));
    end;
  finally
    sl.Free;
  end;
end;

Can you please help cleaning up the function/solution and push upstream?

Edit: removed [BUG] from title

#13 Re: mORMot 1 » Download file from mORMot by click link in browser » 2017-09-28 15:26:01

Yes, you can generate links which point to a method based service.

#15 Re: mORMot 1 » Clear separation of components » 2017-07-14 14:27:32

I'm fine with the internal structure / modules!

Imho we need documentation of the url schema, like for example here: https://postgrest.com/en/latest/api.html.

And someone should finish the openapi/swagger integration.

#16 Re: mORMot 1 » JsonSerialization question » 2016-07-13 06:32:59

Afaik this is not automagically possible.
In my case, client and server had to ignore the dummy fields.

#17 Re: mORMot 1 » JsonSerialization question » 2016-07-12 16:05:57

i had this problem with Delphi 2010, too.
The rtti was missing for some records in an interface-based service.
Adding a dummy field of type string did the job.

#18 Re: mORMot 1 » Default Enumname in Response, not Enumindex » 2016-05-11 13:48:11

We have javascript clients reading and writing enum-names as text.

With current trunk, enum-names, as well as enum-index, as request-paramter are still working, but in the response is the enum-index.

With mORMot-version "mORMot_and_Open_Source_friends_2014-07-02_074115_da7141e88e", Default was enum-name. Using Delphi 2010.

We use the swagger-api to develop the client against. With RawJSON as parameter type we will lose the type-info.

#19 Re: mORMot 1 » Default Enumname in Response, not Enumindex » 2016-05-11 13:09:21

Interface-Based-Service, out-Records containing Enums.

#20 mORMot 1 » Default Enumname in Response, not Enumindex » 2016-05-11 12:26:13

sevo
Replies: 4

How to respond as default with Enumname instead of the Enumindex?
I've found the option TTextWriterOption.twoEnumSetsAsTextInRecord but i don't know how to set this option as default.

#21 Re: mORMot 1 » ToClientDataSet/ToDataSet » 2016-05-03 10:48:53

I would try using Field-Aliases, e.g. "select table1.field1 as localfield ..." and calculate the field-values in OnCalcFields-Event of the existing client-dataset.
Maybe OnCalcFields is not trigged when loading with ToClientDataset.

#22 Re: mORMot 1 » Template for generating Swagger-UI-JSON » 2016-04-28 13:25:13

Hi Arnaud,

i have a small update.
A patch for mORMotWrappers.pas to support some swagger-types in the server-context:

diff --git a/SQLite3/mORMotWrappers.pas b/SQLite3/mORMotWrappers.pas
index 7943ecf..492eedd 100644
--- a/SQLite3/mORMotWrappers.pas
+++ b/SQLite3/mORMotWrappers.pas
@@ -198,7 +198,7 @@ type
     wObject, wSQLRecord, wInterface, wRecordVersion);
   /// supported languages typesets
   TWrapperLanguage = (
-    lngDelphi, lngPascal, lngCS, lngJava, lngTypeScript);
+    lngDelphi, lngPascal, lngCS, lngJava, lngTypeScript, lngSwagger);
 
 const
   CROSSPLATFORM_KIND: array[TSQLFieldType] of TCrossPlatformSQLFieldKind = (
@@ -248,7 +248,27 @@ const
     'mORMot.TModTime', 'mORMot.TCreateTime', 'number', 'number', 'number',
     'mORMot.TDateTime', 'string', 'string', 'any', 'mORMot.TSQLRawBlob',
     'mORMot.TGUID', 'mORMot.THttpBody', '', '', 'any', '', '', '',
-    'mORMot.TRecordVersion'));
+    'mORMot.TRecordVersion'),
+   // lngSwagger
+   ('', // wUnknown,
+    '{"type": "boolean"}', // wBoolean
+    '', '', // wEnum, wSet,
+    '{"type":"integer"}', '{"type":"integer"}', // wByte, wWord,
+    '{"type":"integer"}', '{"type":"integer"}', // wInteger, wCardinal,
+    '{"type":"integer","format":"int64"}', // wInt64
+    '', '', '', '', '', //wID, wReference, wTimeLog, wModTime, wCreateTime,
+    '{"type":"number","format":"double"}', //wCurrency,
+    '{"type":"number","format":"float"}', // wSingle
+    '{"type":"number","format":"double"}', // wDouble
+    '{"type":"string","format":"date-time"}', //wDateTime
+    '{"type":"string"}', //wRawUTF8
+    '{"type":"string"}', //wString
+    '{"type":"object"}', //FIXME! //wRawJSON
+    '{"type":"string","format":"binary"}', //wBlob
+    '{"type":"string"}',  //wGUID
+    '', '', '', '', //wCustomAnswer, wRecord, wArray, wVariant
+    '', '', '', '' //wObject, wSQLRecord, wInterface, wRecordVersion
+    ));
 
   TYPES_ORM: array[TSQLFieldType] of TWrapperType =
     (wUnknown,        // sftUnknown
@@ -773,7 +793,7 @@ begin
     'typeWrapper',typeWrapper^,      'typeSource',typName,
     'typeDelphi',VarName(lngDelphi), 'typePascal',VarName(lngPascal),
     'typeCS',VarName(lngCS),         'typeJava',VarName(lngJava),
-    'typeTS',VarName(lngTypeScript)]);
+    'typeTS',VarName(lngTypeScript), 'typeSwagger',VarName(lngSwagger)]);
   if self=nil then
     exit; // no need to have full info if called e.g. from MVC
   if typInfo<>nil then

And an updated template, using the swagger-types from the server-context and also generating valid json:

{{! WARNUNG: Benötigt gepatchtes mORMot }}
{{<schema-fuer-typ}}
    {{#typeSwagger}}
        {{!HACK: Enums, Records und Arrays, die separat definiert werden und referenziert werden müssen
                 haben den gleichen Swagger- wie Source-Typ. Alle integrierten Typen habe einen eigenen
                 Swagger-Typ}}
        {{#Equals typeSwagger,typeSource}}
            { "$ref": "#/definitions/{{typeSwagger}}" }
        {{/Equals}}
        {{^Equals typeSwagger,typeSource}}
            {{typeSwagger}}
        {{/Equals}}
    {{/typeSwagger}}
    {{^typeSwagger}}
        {{#nestedSimpleArray}}
            { 
                "type": "array",
                "items": {{>schema-fuer-typ}}
            }
        {{/nestedSimpleArray}}
    {{/typeSwagger}}
{{/schema-fuer-typ}}
{
    "swagger": "2.0",
    "info": {
        "description": "Generiert durch mORMot {{mORMotVersion}} am {{time}}",
        "title": "mORMot -> Swagger"
    },
    "host": "{{host}}",
    "basePath": "/{{root}}",
    "tags": [
	  {{#soa}} {{#services}}
		{
			"name": "{{uri}}",
			"description": "Everything about {{uri}}"
		} {{^-last}},{{/-last}} 

	  {{/services}} {{/soa}}
	],
    "definitions": {
        {{! Records }}
      {{#records}}
        "{{name}}": { 
            "type": "object",
            "properties": {
              {{#fields}}
                "{{propName}}": {{>schema-fuer-typ}} {{^-last}},{{/-last}} 
              {{/fields}}
            }
        },
      {{/records}}
        
        {{! Arrays }}
      {{#arrays}}
        "{{name}}": {
            "type": "array",
            "items": {{>schema-fuer-typ}}
        },
      {{/arrays}}
        

{{#enumerates}} 
       "{{name}}": {
          "type": "string",
          "enum": [
               {{#values}}
               "{{.}}" {{^-last}},{{/-last}} 
               {{/values}}
          ],           
          "required": true  
       },
{{/enumerates}}
        {{!HACK: Sonst haben wir ein einzelnes Komma am Schluss }}
        "__dummy__": {"type":"string"}
    },
    "paths": {
      {{#soa}} {{#services}}
      {{#methods}}
        "/{{uri}}/{{methodName}}": {
            "post": {
				"tags": ["{{uri}}"],
                "parameters": [{
                    "in": "body",
                    "name": "body",
                    "schema": {
                        "type": "object",
                        "properties": {
                          {{#args}}{{#dirInput}} 
                            "{{argName}}": {{>schema-fuer-typ}}{{commaInSingle}}
                          {{/dirInput}}{{/args}}
                        }
                    }
                }],
                "responses": {
                    "200": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "result": {
                                    "type": "array",
                                    "items": [
                                        {{#args}} {{#dirOutput}}
                                            {{>schema-fuer-typ}}{{#commaOutResult}},{{/commaOutResult}}
                                        {{/dirOutput}}{{/args}}
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        } {{^-last}},{{/-last}}
      {{/methods}} {{^-last}},{{/-last}}


      {{/services}} {{/soa}}
    }
}

Now it is almost possible to use the client- and server-code generators from swagger with the resulting swagger.json.
There is an open issue with swagger, not allowing inline response-schemata in code-generation.

It would be nice to have the response-format in the server-context, eg. ResultAsJSONObjectWithoutResult, ResultAsJSONObject, Default, XML... to generate the according response-schema for swagger.

Thx!

sevo

#23 Re: mORMot 1 » TSynDBDataSet(ds1.DataSet).ApplyUpdates issue » 2016-04-28 12:39:23

In my case (ODBC-Connection), the changes are applied, but the inserted value is 'null'.
It is not possible to set an empty string or clear the field.

E.g. FieldByName('Field').AsString = '' -> inserts the string 'null'
and FieldByName('Field').Clear -> insterts the string 'null', too.

It ends up in TSQLDBStatement.BindVariant, Default (no match for TVarData(Data).VType) -> VariantToUTF8(undefined) -> 'null'

Is it possible to keep TDataSet-Compatibility here?

#24 Re: mORMot 1 » Template for generating Swagger-UI-JSON » 2016-03-16 07:44:58

Update:
- Services are grouped in seperate sections, not in a single list of all functions anymore.
- Enums are resolved. They are passed as String, e.g. "cicUnknown" and all Enums are listet in the Data-Type -> Model - Section of each function.

HowTo:
- you have to provide the url of the generated .json.txt file to swagger. E.g. http://petstore.swagger.io/?url=http:// … t.json.txt

{{! FIXME: mORMot gibt bei nicht-Array-Typen keine "isArray" Eigenschaft aus,
    und unterstützt die {{.Variable\}\} Notation auch nicht. Somit können verschachtelte Arrays
    hier nicht sauber verarbeitet werden. Das Delphi-Template ist auf gleiche Weise limitiert. }}
{{<schema-fuer-typ}}{{#nestedSimpleArray}}
    { 
        "type": "array",
        "items": { "$ref": "#/definitions/{{typeSource}}" }
    }
{{/nestedSimpleArray}}{{^nestedSimpleArray}}
    { "$ref": "#/definitions/{{typeSource}}" }
{{/nestedSimpleArray}}{{/schema-fuer-typ}}

{
    "swagger": "2.0",
    "info": {
        "description": "Generiert durch mORMot {{mORMotVersion}} am {{time}}",
        "title": "mORMot -> Swagger",
    },
    "host": "{{host}}",
    "basePath": "/{{root}}",
    "tags": [
	  {{#soa}} {{#services}}
		{
			"name": "{{uri}}",
			"description": "Everything about {{uri}}",
		},
	  {{/services}} {{/soa}}
	],
    "definitions": {
        {{! Records }}
      {{#records}}
        "{{name}}": { 
            "type": "object",
            "properties": {
              {{#fields}}
                "{{propName}}": {{>schema-fuer-typ}},
              {{/fields}}
            }
        },
      {{/records}}
        
        {{! Arrays }}
      {{#arrays}}
        "{{name}}": {
            "type": "array",
            "items": {{>schema-fuer-typ}}
        },
      {{/arrays}}
        
      {{#enumerates}} 
          "{{name}}": {
              "type": "string",
              "enum": [
                  {{#values}}
                  {{.}}, 
                  {{/values}}
                  ],           
              "required": true  
          },
      {{/enumerates}}

        {{! HACK: Standard-Datentypen }}
        "Integer": { "type": "integer" },
        "Boolean": { "type": "boolean" },
        "String": { "type": "string" },
        "Double": { "type": "number", "format": "double" },
        "Variant": { "type": "object" } {{! <-- FIXME }}
    },
    "paths": {
      {{#soa}} {{#services}}
      {{#methods}}
        "/{{uri}}/{{methodName}}": {
            "post": {
				"tags": ["{{uri}}"],
                "parameters": [{
                    "in": "body",
                    "name": "body",
                    "schema": {
                        "type": "object",
                        "properties": {
                          {{#args}}{{#dirInput}} 
                            "{{argName}}": {{>schema-fuer-typ}},
                          {{/dirInput}}{{/args}}
                        }
                    }
                }],
                "responses": {
                    "200": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "result": {
                                    "type": "array",
                                    "items": [
                                        {{#args}} {{#dirOutput}}
                                            {{>schema-fuer-typ}},
                                        {{/dirOutput}}{{/args}}
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
      {{/methods}}
      {{/services}} {{/soa}}
    }
}

#25 Re: mORMot 1 » mORMot and winCE » 2016-01-24 19:16:34

EgonHugeist wrote:

@sevo did you try to comile Zeos on WinCE?

no

#26 Re: mORMot 1 » mORMot and winCE » 2016-01-22 19:23:13

I could build a client for WinCE/ARM using fpc 2.6.4 using the crossplatform-code generated by a mORMot server.
Server was interface-based/records-only.

Had some problems with UTF-8 conversion in TextToHttpBody and HttpBodyToText ('?' for umlauts) and changed the conversion to an implicit cast (if at all, i don't know)
//instead of Text := Utf8Decode(utf8)
Text := utf8;

Hope this helps!

#27 mORMot 1 » Template for generating Swagger-UI-JSON » 2015-11-10 16:03:05

sevo
Replies: 32

Hello,

drop the following mustache-template in your Crossplatform/templates folder, open up http://petstore.swagger.io/, select the generated .json file and look at this beautiful, executable, interface-based-service documentation.

For now:
- authentication is not supported (basic-auth should work out of the box)
- only interfaced-based-services are supported
- swagger-types are mapped inside the template
- generated json is not valid, but ok for swagger-ui

Here is the template (swagger.json.mustache):

{{! FIXME: mORMot gibt bei nicht-Array-Typen keine "isArray" Eigenschaft aus,
    und unterstützt die {{.Variable\}\} Notation auch nicht. Somit können verschachtelte Arrays
    hier nicht sauber verarbeitet werden. Das Delphi-Template ist auf gleiche Weise limitiert. }}
{{<schema-fuer-typ}}{{#nestedSimpleArray}}
    { 
        "type": "array",
        "items": { "$ref": "#/definitions/{{typeSource}}" }
    }
{{/nestedSimpleArray}}{{^nestedSimpleArray}}
    { "$ref": "#/definitions/{{typeSource}}" }
{{/nestedSimpleArray}}{{/schema-fuer-typ}}

{
    "swagger": "2.0",
    "info": {
        "description": "Generiert durch mORMot {{mORMotVersion}} am {{time}}",
        "title": "mORMot -> Swagger",
    },
    "host": "{{host}}",
    "basePath": "/{{root}}",
    
    "definitions": {
        {{! Records }}
      {{#records}}
        "{{name}}": { 
            "type": "object",
            "properties": {
              {{#fields}}
                "{{propName}}": {{>schema-fuer-typ}},
              {{/fields}}
            }
        },
      {{/records}}
        
        {{! Arrays }}
      {{#arrays}}
        "{{name}}": {
            "type": "array",
            "items": {{>schema-fuer-typ}}
        },
      {{/arrays}}
        
        {{! HACK: Standard-Datentypen }}
        "Integer": { "type": "integer" },
        "Boolean": { "type": "boolean" },
        "String": { "type": "string" },
        "Double": { "type": "number", "format": "double" },
        "Variant": { "type": "object" } {{! <-- FIXME }}
    },
    "paths": {
      {{#soa}} {{#services}}
      {{#methods}}
        "/{{uri}}/{{methodName}}": {
            "post": {
                "parameters": [{
                    "in": "body",
                    "name": "body",
                    "schema": {
                        "type": "object",
                        "properties": {
                          {{#args}}{{#dirInput}} 
                            "{{argName}}": {{>schema-fuer-typ}},
                          {{/dirInput}}{{/args}}
                        }
                    }
                }],
                "responses": {
                    "200": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "result": {
                                    "type": "array",
                                    "items": [
                                        {{#args}} {{#dirOutput}}
                                            {{>schema-fuer-typ}},
                                        {{/dirOutput}}{{/args}}
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
      {{/methods}}
      {{/services}} {{/soa}}
    }
}

Board footer

Powered by FluxBB