Using more complex objects with XData

I have imported a Swagger using the OpenAPI tool and am looking to create an XData server to reflect that. Some of the classes contain TObjectLists and properties that are objects - for example

TCreateLabelRequest = class
  private
    FServiceProvider: string;
    FLabelSpecification: TLabelSpecification;
    FConsignment: TConsignment;
    FPackages: TPackageList;
    FCustoms: TCustomsData;
    FShipFrom: TAddress;
    FShipTo: TAddress;
    FServiceType: string;
    FServiceOptions: TServiceOptions;
    procedure SetLabelSpecification(const Value: TLabelSpecification);
    procedure SetConsignment(const Value: TConsignment);
    procedure SetPackages(const Value: TPackageList);
    procedure SetCustoms(const Value: TCustomsData);
    procedure SetShipFrom(const Value: TAddress);
    procedure SetShipTo(const Value: TAddress);
    procedure SetServiceOptions(const Value: TServiceOptions);
  public
    constructor Create;
    destructor Destroy; override;
    property ServiceProvider: string read FServiceProvider write FServiceProvider;
    property LabelSpecification: TLabelSpecification read FLabelSpecification write SetLabelSpecification;
    property Consignment: TConsignment read FConsignment write SetConsignment;
    property Packages: TPackageList read FPackages write SetPackages;
    property Customs: TCustomsData read FCustoms write SetCustoms;
    property ShipFrom: TAddress read FShipFrom write SetShipFrom;
    property ShipTo: TAddress read FShipTo write SetShipTo;
    property ServiceType: string read FServiceType write FServiceType;
    property ServiceOptions: TServiceOptions read FServiceOptions write SetServiceOptions;
  end;

Do I need to create a Custom Converter?

No. XData is able to handle the full object automatically. I'd just recommend you add the [JsonManaged] attribute to the class so that XData doesn't try to destroy the associated objects, leaving it to the object itself.

1 Like

Is there a way to test the import of the Json? Or somewhere to breakpoint it?

While the call is succeeding to reach the method and the object is created, there is no data in it.

Thanks

Hard to tell without more detailed information. You can of course try to debug XData code, although that's for advanced users. You can try to intercept the HTTP calls and inspect the JSON received by using a tool like Fiddler.

I've been trying to use WireShark and RawCap, but I'm not getting much joy - obviously have the filters set incorrectly.

I don't mind trying to debug through the XData code, but would be useful to have a place to start - such as where it first sees the content stream from the post.

Thanks

For now, to start with, easiest way is to use Fiddler. Learning to use it is also helpful for any debugging you want to do with TMS Sparkle from Windows. It's much easier and higher-level than WireShark. Never used RawCap. Usually you just need to do this:

  1. Install Fiddler, open it and make sure it's capturing requests (which is on by default when you start it).

  2. Configure WinHttp engine to use automatically use the default proxy.

uses {...}, Sparkle.WinHttp.Engine;

var
  Engine: TWinHttpEngine;
begin
  Engine := TWinHttpEngine(FClient.Engine);
  Engine.ProxyMode := THttpProxyMode.Auto;
  Engine.ResetSession;
end;
  1. Make sure you not access the server using localhost or 127.0.0.1 address otherwise Fiddler will ignore those. Just use, for example, your computer name.

With that you should be able to see exactly the JSON being sent and receive from the server, as well all the HTTP request headers.

Thanks.

I'm just using a plain System.Net.THttpClient to send the body.

I know the call is being received and I have installed Fiddler and the body content (JSON) looks fine.

So where to intercept in the app to see what's happening?

The XData App has a

TSparkleHttpSysDispatcher
TXDataServer
[ServiceImplementation]
TColl8Service = class(TInterfacedObject, IColl8Service)

no aurelius, everything is handled in the service object.

The issue was different casing of some property names.

Although that has led to another issue. I'll detail below, if I can't sort it.

I am getting this error:

Project Coll8ProxyDesktop.exe raised exception class EConvertFromJsonError with message 'Invalid string JSON value at $.customs.commodities[0].weight.unit'.

The object definition is

TConsignmentWeight = class
  private
//    [JsonProperty('unit')]
    FunitOfWeight: string;
    Fvalue: Double;
  public
    [JsonProperty('unit')]
    property unitOfWeight: string read FunitOfWeight write FunitOfWeight;
    property value: Double read Fvalue write Fvalue;
  end;

and the JSON:

"consignment": {
    "weight": {
      "unit": "GRAM",
      "value": 1600.0 
    }

any ideas?

The JsonProperty attribute should be in the class field, not in class property.

Although that's probably not the cause of the error. The error simply indicates that unit property in JSON is not a valid string.

Your error message and JSON don't match. The error message indicates tha the weight object is inside an object that is the first item of an array (commodities). Your JSON doesn't reflect that. So probably you are inspecting the wrong data.

Sorry, copied the wrong JSON section (correct below for reference).

I changed the Jsonproperty attribute as you said and it has worked (I think).

"customs": {
    "commodities": [
      {
        "quantity": 1,
        "description": "GOLF CLUBS",
        "hsCode": "95063100",
        "value": {
          "currency": "EUR",
          "value": 25.0
        },
        "weight": {
          "unit": "KILOGRAM",
          "value": 1.2
        }
      },
      {
        "quantity": 1,
        "description": "Bag of spanners 2",
        "hsCode": "95963100",
        "value": {
          "currency": "EUR",
          "value": 1.0
        },
        "weight": {
          "unit": "KILOGRAM",
          "value": 2.0
        }
      }
    ]
  },

It did work, or it didn't? :slight_smile:

There were 2 changes I made, one was the attribute position (actually I had it in at both the field and property level, so removed the latter), and I also changed the casing of one field, which was not part of this section but a previous one. So not sure which action fixed it.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.