You are not logged in.
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.
Thanks @ab, it's working, I added description to swagger template, later I'll do a pull request.
@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.
I use TWinHttp that is in unit SynCrtSock.pas. I did make a consumer webservice for SOAP and JSON with SSL support.
Thanks
Hi @ab, can you modify AuthenticationCheck function in TSQLRestServerURIContext as virtual ? I need add more checking to the default check.
Thanks.
@ab, this not works, I had to do the following to make it work:
Implement the TSQLRestRoutingREST for override Authenticate function:
/// Clase que implementa una customización del manejo de peticiones REST
TSQLRestRoutingREST_JWT = class(TSQLRestRoutingREST)
protected
// Se incorpora la autenticación con JWT
function Authenticate: boolean; override;
end;
function TSQLRestRoutingREST_JWT.Authenticate: boolean;
begin
Result := inherited Authenticate;
if (not Result) then
Result := (Session = CONST_AUTHENTICATION_SESSION_NOT_STARTED) and (Server.JWTForUnauthenticatedRequest<>nil);
if Result then
Session := CONST_AUTHENTICATION_NOT_USED; //--> force call Ctxt.AuthenticationCheck(fJWTForUnauthenticatedRequest) in TSQLRestServer.URI
end;and I assigned this TSQLRoutingREST to the REST server:
...
// 6. Se crea el servidor REST para poder hacer migraciones si es necesario
// - HandleAuthentication debe ser true para poder manejar usuarios
fRestServer := TARISRestServer.Create(fModel, fARISDB, fConfig.RESTServer.HandleAuthentication);
fRestServer.ServicesRouting := TSQLRestRoutingREST_JWT; //--> custom routing rest class
// - Se permite autenticación/autorización básica (Authorization: Basic ...)
fRestServer.AuthenticationRegister(TSQLRestServerAuthenticationHttpBasic);
// - Se permite JWT para peticiones sin sesión
fRestServer.JWTForUnauthenticatedRequest := TJWTHS256.Create('secret',10,[jrcIssuer,jrcSubject],[]);
...Is this correct this way ? Is there better way ?
Thanks.
I have created the TSQLRestServer.JWTForUnauthenticatedRequest and the interface is defined as sicShared.
For example, this is my code excerpt in the REST server creation:
TARIS.Run // TARIS is a container
...
// 6. Se crea el servidor REST para poder hacer migraciones si es necesario
// - HandleAuthentication debe ser true para poder manejar usuarios
fRestServer := TARISRestServer.Create(fModel, fARISDB, fConfig.RESTServer.HandleAuthentication);
fRestServer.ServicesRouting := TSQLRestRoutingREST_JWT;
// - Se permite autenticación/autorización básica (Authorization: Basic ...)
fRestServer.AuthenticationRegister(TSQLRestServerAuthenticationHttpBasic);
// - Se permite JWT para peticiones sin sesión
fRestServer.JWTForUnauthenticatedRequest := TJWTHS256.Create('secret',10,[jrcIssuer,jrcSubject],[]);
...
end;
TARIS.LoadServices
var
lGroupID: TID;
begin
lGroupID := fRestServer.MainFieldID(TSQLAuthGroupApproach,DEFAULT_GROUP_APP_APPROACH);
fRestServer.ServiceDefine(TDBService, [IDBService], sicShared, CONTRACT_SERVICE_DB).AllowAllByID([lGroupID]);
fRestServer.ServiceDefine(TContactDataService, [IContactDataService], sicShared, CONTRACT_SERVICE_CONTACTDATA).AllowAllByID([lGroupID]);
fRestServer.ServiceDefine(TSchedulerService, [ISchedulerService], sicShared, CONTRACT_SERVICE_SCHEDULER).AllowAllByID([lGroupID]);
...
end;I invoke from client side (testing) in the following way:
var
lResp: SockString;
begin
lResp := TWinHTTP.Post('https://localhost:8898/svc/ContactDataService.UpdateByRecId',
'{"aTableName":"TEST01","aRecId":1,"aData":{"PHONE":"1"}}',
JSON_CONTENT_TYPE_HEADER+sLineBreak+AuthorizationBearer(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsInBhc3N3b3JkIjoic3lub3BzZSIsImlzcyI6IlRlY25vVm96IFMuQS4iL'+
'CJzdWIiOiJBUklTIEpXVCJ9.sYUHk0wIHU-J-Jha5IMyUAaGon-fVKKFjR8oUzcDhSc'));
fVKKFjR8oUzcDhSc'),@lResp);
ShowMessage(lResp);When is executed, the server return 403 error because Ctxt.Authenticate reject by invalid signature.
Is this correct way ?
What else should I do ?
Thanks.
Ok, I can confirm that when calling an interface based service without session signature the invokation never arrives to the service implementation because Ctxt.Authenticate reject by invalid signature. This not allow invoke interface based service with a valid JWT. May be I'm doing something wrong.
If I implement a method based service that return a valid JWT, how invoke then interface based service with these JWT ?
Thanks.
Hi @ab,
I use interfaced based service with session for our applications, but for external integration I need that the user can invoke such services but with JWT, that is, using JWT for validate the request without existing session. Is this posible ?
Thanks.
Use rec.IDValue instead of rec.ID
Thank you very much.
Hi ab, can you add the following HTTP status code mORMot.pas ?
HTTP_CONFLICT = 409;
Thanks.
try this:
function TNotifySrv.Test(notify: UTF8String): UTF8String;rename argument "aXml" to "notify".
Regards.
Esteban
I tried it using fpcupdeluxe but fpcupdeluxe settings could not download it (url is wrong) and after the install when I compiled a simple program "hello" several errors with NativeInt (or something like that) were reported.
On the other hand, will be very good that pas2js support ES6 javascript.
Thanks @hnb, I asked because I read the @ab blog (http://blog.synopse.info/post/2018/02/0 … C-with-FPC) and him use the trunk version of the FPC.
Sorry for my stupid questions, I started to use Lazarus/FPC throught fpcupdeluxe with trunk version and installing mORMot, Zeos, etc. with "Install Module" option de fpcupdeluxe. It is the best way or I must to use NewPascal ?
Thanks.
@edwinsn I use TSynLog.Family.ExceptionIgnore.Add(ExceptionXXX), it is not useful for you ?
Hi @ab, I updated SynRestDataset to latest mORMot version and created a pull request on github.com, but I omitted directory EMartin in ThirdPartyDemos and I renamed TSynRestDataset directory to SynRestDataset. Can you correct this error ?
@xchinjo, I removed the patch with redirectcode.
Thanks.
SynProject and HTMLView folders are not in GitHub.com, is the idea ?
Thanks.
Esteban.
@Junior/RO, I used Fossil, in git are these this files ?
yes, the sqlite3.obj files was the problem.
Sorry and thanks.
Sorry, I did read the article but I forgot that part.
I downloaded and copied all content from zip file to the "static" folder and I put the "static" folder in "Search Path" (Delphi 7) but the error continue. My target and development OS is Windows 32bit.
I'm sure I did something wrong but I don't know what.
Thanks.
Hi @ab, when compiling a project that use sqlite3 the following errors are reported:
Build
[Error] SynSQLite3Static.pas(747): Unsatisfied forward or external declaration: 'CodecGetReadKey'
[Error] SynSQLite3Static.pas(748): Unsatisfied forward or external declaration: 'CodecGetWriteKey'
[Error] SynSQLite3Static.pas(977): Unsatisfied forward or external declaration: 'sqlite3_key'
[Error] SynSQLite3Static.pas(978): Unsatisfied forward or external declaration: 'sqlite3_rekey'
[Error] SynSQLite3Static.pas(1083): Unsatisfied forward or external declaration: 'sqlite3_trace_v2'
[Error] SynSQLite3Static.pas(1): Unsatisfied forward or external declaration: 'winRead'
[Error] SynSQLite3Static.pas(1): Unsatisfied forward or external declaration: 'winWrite'
[Fatal Error] uMain.pas(346): Could not compile used unit 'SynSQLite3Static.pas'with previous version no errors.
This also fails in TestSQL3.dpr
Thanks.
the correct way:
var
lFromNames, lToNames: TRawUTF8DynArray;
begin
SetLength(lFromNames,2);
lFromNames[0] := 'Name1';
lFromNames[1] := 'Name2';
SetLength(lToNames,2);
lToNames[0] := 'ToName1';
lToNames[1] := 'ToName2';
myProcedure(lFromNames, lToNames);
end;EMartin
How do I get access to this property?
you are see a DocVariantData and can access to property in this way:
DocVariantData(variantdoc).value['rowCount']use rowCount property, expanded JSON always return this when the query return empty dataset.
@ab, changing the order works fine, seems to be that there was some change affecting this.
Thanks for the solution.
Maybe my TSynRestDataset in third-party samples can help you.
Thanks @ab, I'll try this but it's strange that @wloochacz this works.
@wloochacz, in SynopseCommit.inc it's the numerical version (latest is 4299).
Please, can you try the app. with latest commit ?
Thanks.
@ab, can you reproduce this issue with the sample app. ? I tried with older commits but the error persist. The log in the sample app. show this:
...
20180216 13582123 $ + mORMot.TSQLRestServerFullMemory(0458F670).URI(POST root/Calculator.TestObjArray?session_signature=523e3fda0007e3ac5b7620eb inlen=21)
20180216 13582123 $ auth TSQLRestRoutingREST(04AE7420) User/1379811290 127.0.0.1
20180216 13582123 $ call mORMot.TSQLRestServerFullMemory(0458F670) ICalculator.TestObjArray[[76976416,76976512]] *** THIS IS THE ERROR ***
20180216 13582123 $ EXCOS EAccessViolation (C0000005) at 004C7788 stack trace 00402F11 0043EA3A 0043DAD1 0043DB9D 0043DDA6 004B45D0 77930637 00402E8C 00402F11 0040667B 004047E6 004B354D 004B1E52 746C7573 00402E8C 0040532D 00405370 00427244 75636C61 7796E7DC 74AB9BA2 74AB9BB3 74AB9AB8 74B21B72 00403460 0040366B 0044648F 00402EB7 00405279 00452CA7
20180216 13582124 $ EXCOS EAccessViolation (C0000005) at 004C7788 stack trace 00402EB7 00483978 004C6991 004BB8B5 004C011E 00420C57 004051FE 76288654 77964A77 77964A47 The AV are when the method in the server side try access to array elements.
I am worry about this behavior, I never had it before.
Thanks.
@woolachz do you have the last commit (4299) ?
@ab I am using Delphi 7 and I cloned the last version of the repository.
I don't think so, my problem is with dynamic arrays as parameter in interface based service, this was working.
Hi @ab, I can reproduce my problem using sample 14-Interface based service. The test case it's in https://drive.google.com/open?id=1UUGBH … lbv0o8njks.
I added
function TestObjArray(const aObjArray: TTestObjArray): RawUTF8;to TServiceCalculator interface service. You can see that the service receives empty aObjArray values (but the length is correct) when the client sent with data.
Please, can you see this issue.
Thanks in advance.
I found the error in my test case, I forgot this code:
TJSONSerializer.RegisterObjArrayForJSON(TypeInfo(TCDIMapFieldOptionArray), TCDIMapFieldOption);I don't understand why the JSON serialization in interface based service is not working more. That's is my big problem.
I'all appreciate any help.
Sorry @ab for my insistence, can you see this issue ?
Thanks.
Sorry @ab, but in the last fixes have been introduced a bug when saving objects to JSON from TDynArray. In https://drive.google.com/open?id=1qCR1x … jx4ev2wLbK I added a button DynArrayObj that plays the fail case.
For me application, this bug is a breaking change and I need that works as before.
UPDATE:
I have the following interface based service:
function ImportTable(cosnt aCSVOptions: TCDICSVOptions; const aTableOptions: TCDITableOptions; const aMapFieldOptions: TCDIMapFieldOptionArray): TServiceCustomAnswer;and before the fixes this services worked ok, but after the same the server receives the aMapFieldOptions parameter of the same way that the reproduced fail test case.
Thanks in advance.
Thanks @ab, all works fine.
@ab, can you see this ?
Thanks.
Hi @ab, I think that I found bugs in TSQLTable.GetJSONValues and TSQLTable.ToDocVariant, how I can
reproduce them I generated an application test case and I put it in https://drive.google.com/open?id=1kBpGl … yWlSm8-GkX.
The second and third button reproduce the problems and in ToDocVariant checking the "Workaround" checkbox solve the same.
Can you verify this please ?
Thanks.
I think that you have existing primary key in the table, mORMot need a primary key and then do you need map existing PK to internal mORMOt PK:
VirtualTableExternalMap(<model>, <TSQLTable>, <TSQLDBConnectionPropertie>, <Table name>).MapFields('ID', <External PK field>).SetOptions([rpmAutoMapKeywordFields, rpmNoCreateMissingTable, rpmNoCreateMissingField]);
We use Firebird with Zeos (SynDBZeos.pas) and tested with heavy load and works very fine.
Interesting and very useful, great works !!!
Works fine.
Thank you.
@ab, can you see the problem ?
Hi @ab, the test case that reproduce the problem is here https://drive.google.com/open?id=1dYnHr … lDFq740vzm
Thanks.
Hi @ab,
I serialize a dynamic RawUTF8 array as JSON, then unserialize the JSON in a TDocVariantData and last element is losed.
The client application serialize to JSON array:
...
fContactDataQueueDynArray: TDynArray;
...
fContactDataQueueDynArray.Init(TypeInfo(TRawUTF8DynArray), fContactDataQueueArray);
... // fill the array
lData := fContactDataQueueDynArray.SaveToJSON; // lData is RawJSON type and fContactDataQueueDynArray content JSON objects
...
fContactService.RestoreContactFromQueue(aTableId, lData); // invoke the remote service
...The server application unserialize from JSON array:
...
lContactDataQueue.InitJSON(aQueue, [dvoJSONObjectParseWithinString]); // lContactDataQueue is TDocVariantData type
...
lCount := lContactDataQueue.Count; // HERE "Count" have one less than the elements in the array
...TDocVariantData.InitJSON with [dvoJSONObjectParseWithinString] option doesn't update correctly the VCount internal property.
The code with problem is:
function TDocVariantData.InitJSONInPlace(JSON: PUTF8Char;
aOptions: TDocVariantOptions; aEndOfObject: PUTF8Char): PUTF8Char;
var EndOfObject: AnsiChar;
Name: PUTF8Char;
NameLen, n: integer;
intnames, intvalues: TRawUTF8Interning;
begin
Init(aOptions);
...
if n>0 then begin
SetLength(VValue,n);
repeat
if VCount>=n then
exit; // unexpected array size means invalid JSON
GetJSONToAnyVariant(VValue[VCount],JSON,@EndOfObject,@VOptions,false);
if JSON=nil then
exit;
if intvalues<>nil then
intvalues.UniqueVariant(VValue[VCount]);
inc(VCount);
until EndOfObject=']';
end else
...my patch:
function TDocVariantData.InitJSONInPlace(JSON: PUTF8Char;
aOptions: TDocVariantOptions; aEndOfObject: PUTF8Char): PUTF8Char;
var EndOfObject: AnsiChar;
Name: PUTF8Char;
NameLen, n: integer;
intnames, intvalues: TRawUTF8Interning;
begin
Init(aOptions);
...
if n>0 then begin
SetLength(VValue,n);
repeat
if VCount>=n then
exit; // unexpected array size means invalid JSON
GetJSONToAnyVariant(VValue[VCount],JSON,@EndOfObject,@VOptions,false);
if JSON=nil then begin
if EndOfObject=']' then // <--- THE PATCH
inc(VCount);
exit;
end;
if intvalues<>nil then
intvalues.UniqueVariant(VValue[VCount]);
inc(VCount);
until EndOfObject=']';
end else
...Surely you can correct this the better way.
Thanks.
I think Server.db refer to SQLite3 database used by the framework, I use external databases (Firebird, MS SQL, Oracle, Informix) and I create TSQLDBConnectionProperties to refer them.