JSON Guide for Delphi / TMS Web Core

Comprehensive guide to JSON handling in Delphi VCL and TMS WEB Core (pas2js) applications.

Contents

VCL JSON (System.JSON)

Standard Delphi uses System.JSON unit with TJSONObject, TJSONArray, TJSONValue classes.

Parsing

USES System.JSON;

VAR
   JSONObj: TJSONObject;
   JSONValue: TJSONValue;
   Name: STRING;
   Age: Integer;
BEGIN
   JSONValue := TJSONObject.ParseJSONValue(JSONString);
   TRY
      IF JSONValue IS TJSONObject THEN
         BEGIN
            JSONObj := JSONValue AS TJSONObject;
            Name := JSONObj.GetValue<STRING>('name');
            Age := JSONObj.GetValue<Integer>('age');
         END;
   FINALLY
      JSONValue.Free;
   END;
END;

Building

VAR
   JSONObj: TJSONObject;
   JSONArray: TJSONArray;
BEGIN
   JSONObj := TJSONObject.Create;
   TRY
      JSONObj.AddPair('name', 'John');
      JSONObj.AddPair('age', TJSONNumber.Create(30));
      
      JSONArray := TJSONArray.Create;
      JSONArray.Add('item1');
      JSONArray.Add('item2');
      JSONObj.AddPair('items', JSONArray);
      
      Result := JSONObj.ToJSON;
   FINALLY
      JSONObj.Free;  /// Frees child objects too
   END;
END;

TMS Web Core JSON (JS unit)

TMS WEB Core uses native JavaScript objects via the JS unit. Different approach from VCL.

Key Types

TypeDescription
TJSObjectJavaScript object (key-value pairs)
TJSArrayJavaScript array
TJSJSONJSON parsing/stringifying class
JSValueAny JavaScript value

Parsing

USES JS, Web;

VAR
   Obj: TJSObject;
   Name: STRING;
   Age: Integer;
BEGIN
   Obj := TJSJSON.parseObject(JSONString);
   Name := STRING(Obj['name']);
   Age := Integer(Obj['age']);
END;

Building

VAR
   Obj: TJSObject;
   Arr: TJSArray;
   JSONString: STRING;
BEGIN
   Obj := TJSObject.new;
   Obj['name'] := 'John';
   Obj['age'] := 30;
   
   Arr := TJSArray.new;
   Arr.push('item1');
   Arr.push('item2');
   Obj['items'] := Arr;
   
   JSONString := TJSJSON.stringify(Obj);
END;

Parsing JSON

TMS Web Core - Safe Property Access

/// Check if property exists
IF Obj.hasOwnProperty('optionalField') THEN
   Value := STRING(Obj['optionalField'])
ELSE
   Value := 'default';

/// Or use JS undefined check
IF NOT isUndefined(Obj['optionalField']) THEN
   Value := STRING(Obj['optionalField']);

Nested Objects

/// TMS Web Core
VAR
   Config: TJSObject;
   Database: TJSObject;
   Host: STRING;
BEGIN
   Config := TJSJSON.parseObject(JSONString);
   Database := TJSObject(Config['database']);
   Host := STRING(Database['host']);
END;

Type Casting

/// TMS Web Core - explicit casts required
IntValue := Integer(Obj['count']);           /// Number to Integer
FloatValue := Double(Obj['price']);          /// Number to Double
StrValue := STRING(Obj['name']);             /// String
BoolValue := Boolean(Obj['active']);         /// Boolean
ArrValue := TJSArray(Obj['items']);          /// Array
ObjValue := TJSObject(Obj['nested']);        /// Object

Building JSON

TMS Web Core - Object Literal Style

/// Using TJSObject.new
VAR
   Obj: TJSObject;
BEGIN
   Obj := TJSObject.new;
   Obj['id'] := 123;
   Obj['name'] := 'Test';
   Obj['enabled'] := True;
   Obj['tags'] := TJSArray._of('tag1', 'tag2', 'tag3');
END;

TMS Web Core - From Template

/// Parse a template and modify
VAR
   Template: TJSObject;
BEGIN
   Template := TJSJSON.parseObject('{
      "type": "card",
      "width": 300,
      "height": 200
   }');
   Template['width'] := 400;  /// Override
END;

Working with Arrays

TMS Web Core - Array Iteration

VAR
   Arr: TJSArray;
   Index: Integer;
   Item: TJSObject;
BEGIN
   Arr := TJSArray(Obj['items']);
   FOR Index := 0 TO Arr.Length - 1 DO
      BEGIN
         Item := TJSObject(Arr[Index]);
         ProcessItem(STRING(Item['name']));
      END;
END;

Array Creation

/// Empty array
Arr := TJSArray.new;

/// With initial values
Arr := TJSArray._of(1, 2, 3, 4, 5);
Arr := TJSArray._of('a', 'b', 'c');

/// Push items
Arr.push(NewItem);
Arr.push(TJSObject.new);  /// Push object

Array Methods

Arr.Length;           /// Number of items
Arr.push(Item);       /// Add to end
Arr.pop;              /// Remove from end
Arr.shift;            /// Remove from start
Arr.unshift(Item);    /// Add to start
Arr.splice(2, 1);     /// Remove 1 item at index 2

Best Practices

VCL: Always Free JSON Objects

/// VCL - TJSONObject owns children, Free once
JSONObj := TJSONObject.ParseJSONValue(Str) AS TJSONObject;
TRY
   /// Use JSONObj
FINALLY
   JSONObj.Free;
END;

TMS: No Memory Management Needed

/// TMS Web Core - JavaScript GC handles cleanup
Obj := TJSJSON.parseObject(Str);
/// Just use it, no Free needed

Cross-Platform Code

{$IFDEF PAS2JS}
/// TMS Web Core version
Obj := TJSJSON.parseObject(JSONString);
Value := STRING(Obj['field']);
{$ELSE}
/// VCL version
JSONObj := TJSONObject.ParseJSONValue(JSONString) AS TJSONObject;
TRY
   Value := JSONObj.GetValue<STRING>('field');
FINALLY
   JSONObj.Free;
END;
{$ENDIF}
VCL vs TMS: The JSON APIs are completely different between VCL (System.JSON) and TMS Web Core (JS unit). Use $IFDEF PAS2JS to write cross-platform code.