You are not logged in.
Pages: 1
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}}
}
}
Last edited by sevo (2016-04-28 12:42:54)
Offline
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}}
}
}
Last edited by sevo (2016-03-16 07:47:50)
Offline
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
Offline
@ab, what about this ?
And, is possible to use descriptions from endpoint services (/// and // - and // !) to put in Swagger ?
Ok, I found how generate descriptions, I made two mistakes:
1. I put wrong path
2. There is a bug in mORMotWrappers.pas:
constructor TWrapperContext.CreateFromModel(aServer: TSQLRestServer;
const aSourcePath, aDescriptions: TFileName);
var t,f,s,n: integer;
...
begin
Create(aDescriptions);
if aSourcePath<>'' then begin
src := pointer(aSourcePath);
n := 0;
repeat
source := GetNextItemString(src,';');
if (source<>'') and DirectoryExists(source) then begin
SetLength(fSourcePath,n+1);
fSourcePath[n] := IncludeTrailingPathDelimiter(source); //--> CHANGE aSourcePath by source
inc(n);
end;
until src=nil;
end;
fServer := aServer;
TDocVariant.NewFast([@fields,@services]);
// compute ORM information
for t := 0 to fServer.Model.TablesMax do begin
...
Thanks.
Last edited by EMartin (2019-02-20 20:04:35)
Esteban
Offline
Please check https://synopse.info/fossil/info/54a25979af
See also https://synopse.info/fossil/info/8017576d06 as preliminary Swagger support.
Offline
Does it mean we can now use https://swagger.io/tools/swagger-codegen/ to generate, for example, JavaScript client library that can talk to your mORMot rest server?
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
Thanks @ab, it's working, I added description to swagger template, later I'll do a pull request.
Esteban
Offline
Hi @ab, can you add this line in swagger template ? this modification allow view the method description in swagger.io.
...
"paths": {
{{#soa}} {{#services}}
{{#methods}}
"/{{uri}}/{{methodName}}": {
"post": {
"description": {{jsonQuote methodDescription}}, //--> ADD THIS LINE
"tags": ["{{uri}}"],
"parameters": [{
"in": "body",
"name": "body",
"schema": {
"type": "object",
"properties": {
{{#args}}{{#dirInput}}
"{{argName}}": {{>schema-fuer-typ}}{{commaInSingle}}
{{/dirInput}}{{/args}}
}
}
}],
"responses": {
...
Thanks.
Esteban
Offline
Please check https://synopse.info/fossil/info/ae70047bd5
Offline
How to generate method/param descriptions for swagger-UI?
Many Thanks!
Offline
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
Last edited by sevo (2019-02-28 10:23:32)
Offline
Thanks @sevo.
I can assure that enumDescription is not filled in mORMotWrapper.pas and it's very likely the other types aren't either.
Esteban
Offline
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
Offline
@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.
Offline
Unable to display Unicode characters correctly and How to fix it?
Many thanks.
type
/// comment
ITest = interface(IInvokable)
['{3C7A4F39-88C2-4A10-9BC1-1B8AB0FFC5FB}']
///中文,こんにちは, 안녕하세요
function Hello(aName: RawUTF8): RawUTF8;
end;
Last edited by delphi_911 (2019-03-07 09:32:10)
Offline
Thanks @ab, it's OK now. I use XE10.2, it does not store pas files as UTF-8 by default.
Offline
Another question: [array of const] in param, a error: "TJSONRecordRTTI.Create: error when retrieving enhanced RTTI for TVarRec", any suggestion?
Thanks.
Offline
Array of const are not handled as kind of parameters.
See https://synopse.info/files/html/Synopse … l#TITL_154
Use RawJSON or a TDocVariant instead.
Offline
How do I declare my functions so that Swagger can correctly categorize them? Currently, I only have POSTs in the documentation while some functions are GET or DELETE.
My published functions are declared as follows:
function GET_xxxx(const AValue1, AValue2: RawUTF8): TServiceCustomAnswer;
function POST_xxxx(const AValue: RawUTF8): TServiceCustomAnswer;
Offline
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.
Offline
If I understand correctly, using TServiceCustomAnswer, I have to write my own wrapper to correctly generate the data to swagger?
Offline
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.
Offline
Ok, thanks.
Offline
TServiceCustomAnswer could return anything: JSON, binary, picture, video, HTTP redirection...
So there is no way to use RTTI to know what mORMotWrapper should say.
Writing a comment as documentation (///) is indeed the way to deal with TServiceCustomAnswer.
Offline
Hi ab ,I changed the "Swagger.json.mustache",They can get all Objects and paths to test records
(huge code deleted to follow forum rules)
Offline
Thanks for your contribution.
One problem is that you deleted the record serialization definitions in your modification.
BUT please follow the forum rules and don't put huge piece of code (or template) in the forum itself.
https://synopse.info/forum/misc.php?action=rules
The way to do it is either to put a link to gist/pastebin/... or even better make a GitHub pull request.
Offline
Please check https://synopse.info/fossil/info/c60b5cabe2
Offline
Please check https://synopse.info/fossil/info/c60b5cabe2
Please confirm:
If TNullable* types in TSQLRecord(ORM Record), unable to generate correct JSON.
THANKS!
Offline
Pages: 1