/// remote access to a mORMot server using SynCrossPlatform* units {{#uri}} // - retrieved from {{protocol}}://{{host}}/{{uri}} // at {{time}} using "{{templateName}}" template {{/uri}} {{^uri}} // - generated at {{time}} {{/uri}} unit {{fileName}}; { WARNING: This unit has been generated by a mORMot {{mORMotVersion}} server. Any manual modification of this file may be lost after regeneration. Synopse mORMot framework. Copyright (C) {{year}} Arnaud Bouchez Synopse Informatique - http://synopse.info This unit is released under a MPL/GPL/LGPL tri-license, and therefore may be freely included in any application. This unit would work on Delphi 6 and later, under all supported platforms (including MacOSX, and NextGen iPhone/iPad), and the Free Pascal Compiler. } interface uses SynCrossPlatformJSON, SynCrossPlatformSpecific, SynCrossPlatformREST; {{! recursive partials used to write records type definition}} {{writerec}}{{nestedIdentation}} end;{{/nestedRecord}}{{#nestedSimpleArray}}array of {{typePascal}};{{/nestedSimpleArray}}{{#nestedRecordArray}}array of {{>writerec}}{{nestedIdentation}} end;{{/nestedRecordArray}} {{/fields}}{{/writerec}} {{#withEnumerates}} type // define some enumeration types, used below {{#enumerates}} {{name}} = ({{#values}}{{.}}{{^-last}}, {{/-last}}{{/values}}); {{/enumerates}} {{/withEnumerates}} {{#withSets}} type // define some set types, used below {{#sets}} {{name}} = set of({{#values}}{{.}}{{^-last}}, {{/-last}}{{/values}}); {{/sets}} {{/withSets}} {{#withRecords}} type // define some record types, used as properties below {{#records}} {{name}} = {{>writerec}} end; {{/records}} {{/withRecords}} {{#withArrays}} type // define some dynamic array types, used as properties below {{#arrays}} {{name}} = array of {{typeSource}}; {{/arrays}} {{/withArrays}} {{method}} {{/methods}} end; /// implements I{{interfaceURI}} {{#uri}}from {{protocol}}://{{host}}/{{root}}/{{uri}}{{/uri}} // - this service will run in sic{{instanceCreationName}} mode TService{{interfaceURI}} = class(TServiceClientAbstract{{#isClientDriven}}ClientDriven{{/isClientDriven}},I{{interfaceURI}}) public constructor Create(aClient: TSQLRestClientURI); override; {{#methods}} {{verb}} {{>method}} {{/methods}} end; {{/soa.services}} const /// the server port{{#uri}}, corresponding to {{protocol}}://{{host}}{{/uri}} SERVER_PORT = {{port}}; /// the server model root name{{#uri}}, corresponding to {{protocol}}://{{host}}{{/uri}} SERVER_ROOT = '{{root}}'; /// return the database Model corresponding to this server function GetModel(const aRoot: string=SERVER_ROOT): TSQLModel; /// create a TSQLRestClientHTTP instance and connect to the server // - it will use by default port {{port}} over root '{{root}}'{{#host}}, corresponding // to {{protocol}}://{{host}}/{{root}}{{/host}} {{#authClass}} // - secure connection will be established via {{.}} // with the supplied credentials - on connection or authentication error, // this function will raise a corresponding exception {{/authClass}} function GetClient(const aServerAddress{{#authClass}}, aUserName,aPassword{{/authClass}}: string; aServerPort: integer=SERVER_PORT; const aServerRoot: string=SERVER_ROOT; aHttps: boolean={{#https}}true{{/https}}{{^https}}false{{/https}}): TSQLRestClientHTTP; {{#withHelpers}} // publish some low-level helpers for variant conversion // - used internally: you should not need those functions in your end-user code {{#enumerates}} function Variant2{{name}}(const _variant: variant): {{name}}; {{/enumerates}} {{#records}} function Variant2{{name}}(_variant: variant): {{name}}; function {{name}}2Variant(const _record: {{name}}): variant; {{/records}} {{#arrays}} function Variant2{{name}}(const _variant: variant): {{name}}; function {{name}}2Variant(const _array: {{name}}): variant; {{/arrays}} {{/withHelpers}} implementation {$HINTS OFF} // for H2164 hints of unused variables {{#withEnumerates}} { Some helpers for enumerates types } {{#enumerates}} function Variant2{{name}}(const _variant: variant): {{name}}; begin result := {{name}}(VariantToEnum(_variant,[{{#values}}'{{.}}'{{^-last}},{{/-last}}{{/values}}])); end; {{/enumerates}} {{/withEnumerates}} {{#withRecords}} {{setrec}}{{/nestedRecord}}{{#fromVariant}} result.{{fullPropName}} := {{fromVariant}}(_variant.{{fullPropName}}); {{/fromVariant}}{{#nestedSimpleArray}} _arr := JSONVariantDataSafe(_variant.{{fullPropName}},jvArray); SetLength(result.{{fullPropName}},_arr^.Count); for _a := 0 to high(result.{{fullPropName}}) do result.{{fullPropName}}[_a] := {{#fromVariant}}{{fromVariant}}({{/fromVariant}}_arr^.Values[_a]{{#fromVariant}}){{/fromVariant}}; {{/nestedSimpleArray}}{{#nestedRecordArray}} _arr := JSONVariantDataSafe(_variant.{{fullPropName}},jvArray); SetLength(result.{{fullPropName}},_arr^.Count); for _a := 0 to high(result.{{fullPropName}}) do with result.{{fullPropName}}[_a] do begin {{#fields}} {{propName}} := {{#fromVariant}}{{fromVariant}}({{/fromVariant}}_arr^.Values[_a].{{propName}}{{#fromVariant}}){{/fromVariant}}; {{/fields}} end; {{/nestedRecordArray}}{{/fields}}{{/setrec}} {{getrec}}{{/nestedRecord}}{{#toVariant}} res.SetPath('{{fullPropName}}',{{toVariant}}(_record.{{fullPropName}})); {{/toVariant}}{{#nestedSimpleArray}} with res.EnsureData('{{fullPropName}}')^ do for i := 0 to high(_record.{{fullPropName}}) do AddValue({{#toVariant}}{{toVariant}}({{/toVariant}}_record.{{fullPropName}}[i]{{#toVariant}}){{/toVariant}}); {{/nestedSimpleArray}}{{#nestedRecordArray}} with res.EnsureData('{{fullPropName}}')^ do for i := 0 to high(_record.{{fullPropName}}) do with AddItem^, _record.{{fullPropName}}[i] do begin {{#fields}} AddNameValue('{{propName}}',{{#toVariant}}{{toVariant}}({{/toVariant}}{{propName}}{{#toVariant}}){{/toVariant}}); {{/fields}} end; {{/nestedRecordArray}}{{/fields}}{{/getrec}}{ Some helpers for record types } {{#records}} function Variant2{{name}}(_variant: variant): {{name}}; var _a: integer; _arr: PJSONVariantData; begin {{>setrec}} end; function {{name}}2Variant(const _record: {{name}}): variant; var i: integer; res: TJSONVariantData; begin res.Init; {{>getrec}} result := variant(res); end; {{/records}} {{/withRecords}} {{#withArrays}} { Some helpers for dynamic array types } {{#arrays}} function Variant2{{name}}(const _variant: variant): {{name}}; var i: integer; arr: PJSONVariantData; begin arr := JSONVariantDataSafe(_variant,jvArray); SetLength(result,arr^.Count); for i := 0 to arr^.Count-1 do result[i] := {{#fromVariant}}{{fromVariant}}{{/fromVariant}}(arr^.Values[i]); end; function {{name}}2Variant(const _array: {{name}}): variant; var i: integer; res: TJSONVariantData; begin res.Init; for i := 0 to high(_array) do res.AddValue({{#toVariant}}{{toVariant}}{{/toVariant}}(_array[i])); result := variant(res); end; {{/arrays}} {{/withArrays}} {$HINTS ON} // for H2164 hints of unused variables function GetModel(const aRoot: string): TSQLModel; begin result := TSQLModel.Create([{{#orm}}{{className}}{{comma}}{{/orm}}],aRoot); end; function GetClient(const aServerAddress{{#authClass}}, aUserName,aPassword{{/authClass}}: string; aServerPort: integer; const aServerRoot: string; aHttps: boolean): TSQLRestClientHTTP; begin result := TSQLRestClientHTTP.Create(aServerAddress,aServerPort, GetModel(aServerRoot),true,aHttps); // aOwnModel=true try if (not result.Connect) or (result.ServerTimeStamp=0) then raise ERestException.CreateFmt('Impossible to connect to %s:%d server', [aServerAddress,aServerPort]); {{#authClass}} if not result.SetUser({{.}},aUserName,aPassword) then raise ERestException.CreateFmt('%s:%d server rejected "%s" credentials', [aServerAddress,aServerPort,aUserName]); {{/authClass}} except result.Free; raise; end; end; {{#soa.services}} { TService{{interfaceURI}} } constructor TService{{interfaceURI}}.Create(aClient: TSQLRestClientURI); begin fServiceName := '{{interfaceURI}}'; fServiceURI := '{{uri}}'; fInstanceImplementation := sic{{instanceCreationName}}; fContractExpected := '{{contractExpected}}'; inherited Create(aClient); end; {{#methods}} {{verb}} TService{{interfaceURI}}.{{>method}} var res: TVariantDynArray; begin fClient.CallRemoteService(self,'{{methodName}}',{{ArgsOutputCount}}, // raise EServiceException on error [{{#args}}{{#dirInput}}{{#toVariant}}{{toVariant}}({{argName}}){{/toVariant}}{{^toVariant}}{{argName}}{{/toVariant}}{{commaInSingle}}{{/dirInput}}{{/args}}],res{{#resultIsServiceCustomAnswer}},true{{/resultIsServiceCustomAnswer}}); {{#args}}{{#dirOutput}}{{#isObject}} {{argName}}.Free; // avoid memory leak {{/isObject}} {{argName}} := {{#fromVariant}}{{fromVariant}}({{/fromVariant}}res[{{indexOutResult}}{{#fromVariant}}){{/fromVariant}}; {{/dirOutput}}{{/args}}end; {{/methods}} {{/soa.services}} end.