Monday, 17 April 2023
  15 Replies
  875 Visits
  Subscribe
Hello,

we have evaluated your OpenAPI generator. The generated code is really well so far. But we had also identified, that it can't handle Dictionaries which are declared by additionalProperties in OAS 3 (https://swagger.io/docs/specification/data-models/dictionaries/)

For example, the following spec:

"Metadata":{"type":"object","additionalProperties":{"maxLength":500,"type":"string"}}


Is rendered to this "empty" class:

TsgcOpenAPI_Metadata_Class = class(TsgcOpenAPIClass)
private
public
class function Read(const aValue: string): TsgcOpenAPI_Metadata_Class;
public
end;


Do you have any plans to implement the support for additionalProperties?

Best regards from Germany,
Waldemar Derr
1 year ago
·
#1541
Hi,

Could you provide the full spec with this data? I will test here and implement for the next release if needed.

Kind Regards,
Sergio
1 year ago
·
#1542
Thank you for the fast response!

Here you go: 😃
https://dashboard.fiskaly.com/api/v0/spec.json
1 year ago
·
#1543
Hi,

Thanks for the link, I'll read the documentation and try to implement it. I will let you know.

Kind Regards,
Sergio
11 months ago
·
#1571
Hello,

Unfortunately the JSON parser doesn't allow to parse Dictionaries in a standard way, the Embarcaderon JSON adds some additional properties and although I tried to implement custom interceptors the result was not the desired, so finally I implemented a partial support for Additional Properties, this is explained in the following article:

https://www.esegece.com/help/sgcWebSockets/#t=OpenAPI%2FParser%2FSchemas%2FOpenAPI_Additional_Properties.htm

Kind Regards,
Sergio
11 months ago
·
#1573
Hi Sergio,

thank you for this release.

I have read your article, some times, but still don't understand how the way from JSON to AdditionalProperties works.

Given this JSON:

{
"_id": "5b8cb290-0901-4435-9131-576695fab511",
"metadata": {
"KdNr": "10001",
"AdGuid": "420739B4-3B2F-4DD1-BCB2-48997EEE930C"
}
}


and this generated classes:


TsgcOpenAPI_Metadata_Class = class(TsgcOpenAPI_AdditionalProperties)
public
class function Read(const aValue: string): TsgcOpenAPI_Metadata_Class;
end;

TsgcOpenAPI_OrganizationResponse_Class = class(TsgcOpenAPIClass)
private
F_id: string;
[sgcAdditionalProperties]
Fmetadata: TsgcOpenAPI_Metadata_Class;
public
class function Read(const aValue: string): TsgcOpenAPI_OrganizationResponse_Class;
public
property _id: string read F_id write F_id;
property Metadata: TsgcOpenAPI_Metadata_Class read Fmetadata write Fmetadata;
end;


After the successful request, Metadata is always nil.

Can you give me an example, how it should work?
11 months ago
·
#1574
Hello,

Using the following code, works well


var
i: Integer;
oResponse: TsgcOpenAPI_OrganizationResponse_Class;
begin
oResponse := TsgcOpenAPI_OrganizationResponse_Class.Read(
' {"_id": "5b8cb290-0901-4435-9131-576695fab511", "metadata": {"KdNr": "10001", "AdGuid": "420739B4-3B2F-4DD1-BCB2-48997EEE930C"}}');
for i := 0 to oResponse.Metadata.Dictionary.Count - 1 do
begin
ShowMessage(oResponse.Metadata.Dictionary.ToArray[i].Key + '=' + oResponse.Metadata.Dictionary.ToArray[i].Value);
end;


Which method are you using to send the request? Retrieve_Organization?

Kind Regards,
Sergio
11 months ago
·
#1575
Hi,

I have tried...in your example, after TsgcOpenAPI_OrganizationResponse_Class.Read, oResponse.Metadata is nil. I would post a screenshot, but it isn't possible to upload images here.

Further I don't understand how it could work if the ObjectReverter is implemented as follows:


procedure TsgcAdditionalPropertiesInterceptor.ObjectReverter(Data: TObject;
Field: string; Arg: TObject);
begin
inherited ObjectReverter(Data, Field, Arg);
end;


and the inherited method in REST.JsonReflect is empty.

Maybe some code is not released?
11 months ago
·
#1576
Hi,

I am not using the ObjectReverter because as I told in a previous message, the Embarcadero JSON implementation doesn't allow to read a JSON Dictionary in a standard way. I just let this code if later I can found a workarround, but now it's not used.
Could you send me the JSON response you get? and which HTTP method are you requesting? I will test here.

Kind Regards,
Sergio
11 months ago
·
#1577
Hi,

if you say that your example works for you, how is Metadata/TsgcOpenAPI_AdditionalProperties unserialized?

I'm confused of the real code and your statement, I must oversee something.

Ok, but here is the Json:

{
"_id": "5b8cb290-0901-4435-9131-576695fab511",
"_type": "MANAGED_ORGANIZATION",
"_envs": [
"TEST"
],
"name": "Autogenerated-1",
"display_name": "Autogenerated-Kunde Nr. 1",
"address_line1": "Maingosse 1a",
"zip": "12345",
"town": "Berlin",
"country_code": "DEU",
"billing_options": {
"withhold_billing": true,
"bill_to_organization": "87fe7d03-7e90-4e5c-860f-21cc7e5bf436"
},
"metadata": {
"KdNr": "10001",
"AdGuid": "420739B4-3B2F-4DD1-BCB2-48997EEE930C"
},
"managed_by_organization_id": "87fe7d03-7e90-4e5c-860f-21cc7e5bf436",
"created_by_user": "d1e2fe75-6abe-4466-8690-3078b1c4285b"
}


The call was made from this (generated) code:

function TFiskalyManagementOpenApi.retrieveOrganization(aOrganization_id: string): TsgcOpenAPI_retrieveOrganization_Response;
begin;

result := TsgcOpenAPI_retrieveOrganization_Response.Create;
_retrieveOrganization(aOrganization_id, result);
if result.IsSuccessful then
result.Successful := TsgcOpenAPI_OrganizationResponse_Class.Read(result.ResponseText)
else
begin
case result.ResponseCode of
401: result.Error401 := TsgcOpenAPI_retrieveOrganization_ResponseError401_Class.Read(result.ResponseError);
403: result.Error403 := TsgcOpenAPI_retrieveOrganization_ResponseError403_Class.Read(result.ResponseError);
404: result.Error404 := TsgcOpenAPI_retrieveOrganization_ResponseError404_Class.Read(result.ResponseError);
end;
end;

end;


and here also the generated protected method

function TFiskalyManagementOpenApi._retrieveOrganization(aOrganization_id: string; const aResponse: TsgcOpenAPIResponse = nil): string;
var
oRequest: TsgcOpenAPIRequest;
begin
oRequest := TsgcOpenAPIRequest.Create;
Try
oRequest.Method := oapiHttpGET;
oRequest.Endpoint := '/organizations/{organization_id}';
oRequest.Security := oapiSecurityToken;

oRequest.Parameters.Add('organization_id', aOrganization_id, oapiInPath, true);

result := DoHTTP_REQUEST(oRequest, aResponse);
Finally
sgcFree(oRequest);
end;
end;


I hope this helps...
11 months ago
·
#1578
Hi,

I see the problem, one unit was not synchronized, so it was not working as expected, it was my fault. I've recompiled the setup, so please download again and reimport the openAPI specification.

The Metadata dictionary is unserialized in the method: TsgcOpenAPI_OrganizationResponse_Class.Read


class function TsgcOpenAPI_OrganizationResponse_Class.Read(const aValue: string): TsgcOpenAPI_OrganizationResponse_Class;
begin
result := TJson.JsonToObject<TsgcOpenAPI_OrganizationResponse_Class>(aValue);
result.SetRawText(aValue);
if not Assigned(result.metadata) then
result.metadata := TsgcOpenAPI_Metadata_Class.Create;
result.metadata.DoLoadDictionary('metadata', aValue);
end;


Sorry for the inconvenience.

Kind Regards,
Sergio
11 months ago
·
#1581
Hi Sergio,

now it works. Thank you!

But I am afraid that the solution is very inefficient, because for each dictionary the DoLoadDictionary is called which gets the raw Json, so the not so cheap unmarshalling process is done again and again.

For now I can live with this solution, but maybe I find an other way, an efficient one.
It return, maybe we can get the sources for the OpenAPI parser? ;-)
11 months ago
·
#1582
Sorry, the previous post was posted by me (Waldemar Derr), not by Steffen! I forgotten to logout!
11 months ago
·
#1584
Hi,

Yes, I know it's not a good solution, but after working several days with that I finally implement this temporary solution until I find something better. If you find a better solution I will appreciate if you share it. Thanks for the feedback.

Kind Regards,
Sergio
11 months ago
·
#1588
Hi Sergio,

the REST.JsonReflect framework already creates an TsgcOpenAPI_AdditionalProperties when it parses the Json, but it is ignored by the TsgcAdditionalPropertiesInterceptor and is also not released (next memory leak).

So I have the following suggest for this issue:


procedure TsgcAdditionalPropertiesInterceptor.ObjectReverter(Data: TObject; Field: string; Arg: TObject);
var
ctx: TRTTIContext;
begin
if Arg is TsgcOpenAPI_AdditionalProperties then
ctx.GetType(Data.ClassType).GetField(Field).SetValue(Data,Arg);
end;


Best Regards
Waldemar
11 months ago
·
#1589
Hi,

Yes, you are right, there was a memory leak there. I've updated the latest beta with your fix, thanks again for the feedback.

Kind Regards,
Sergio
  • Page :
  • 1
There are no replies made for this post yet.
Submit Your Response
Upload files or images for this discussion by clicking on the upload button below.
Supported: gif,jpg,png,jpeg,zip,rar,pdf
· Insert · Remove
  Upload Files (Maximum 10MB)