Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON data structure - JSON to objects - best practice

I am struggling with my web-application design using JSON, ASP.NET, typescript/javascript and AngularJS.

In Short: I need a best-practice for sending data from the server to a client via JSON, using the JSON-string on the client side to create objects.

I have a WebServerAPI project (ASP.NET) with the following structure:

  • Controllers
    • DataController (REST API)
  • Model
    • A
    • Type

The model classes:

public class A {
    public property int Id {get; set;}
    public property string Name {get; set;}
    public property Type Type {get; set;}
}

public class Type {
    public property int Id {get; set;}
    public property string Name {get; set;}
}

The id of each model class belongs to an id in a database table (primary key).

The DataController structure:

public class DataController : ApiController {
    // ...
    // GET api/a
    public IEnumerable<A> Get()
    {
        // fetches all As from the database
        // the facade creates instances of A and Type as required
        // (if A has a 'Type' the Type will also fetched an set)
        return facade.GetAll<A>();
    }
    // ...
}

The Get() Method of the DataController returns a JSON result.

The JSON result looks like the following:

[
    {"Id":1,
     "Type": {"Id":1, "Name":"name1"}
    },
    {"Id":2,
     "Type": {"Id":2, "Name":"name2"}
    },
    {"Id":3,
     "Type": {"Id":1, "Name":"name1"}
    }
    {"Id":4,
     "Type": {"Id":2, "Name":"name2"}
    },
    {"Id":5,
     "Type": {"Id":2, "Name":"name2"}
    },  
]

As you can see in the JSON data some As share the same Types. Although this is valid JSON, I wonder if this is the best practice to send data.

Wouldn't it be better to send something like this:

[
    {"Id":1,
     "TypeId": {"Id":1}
    },
    {"Id":2,
     "TypeId": {"Id":2}
    },
    {"Id":3,
     "TypeId": {"Id":1}
    }
    {"Id":4,
     "TypeId": {"Id":2}
    },
    {"Id":5,
     "TypeId": {"Id":2}
    },  
]

So we get only the Id of the Type. But then we have to request all available Types to identify which Type has to be set in the corresponding As. Which may be bad? I think this might be slow, because I have to send two queries.

A third option may be sending all available Types and the As in the same JSON result.

[
    {"Types": 
        [
                {"Id":1, "Name":"name1"},
                {"Id":2, "Name":"name2"},
        ]
    },
    {"As":
        [
            {"Id":1,
            "TypeId": {"Id":1}
            },
            {"Id":2,
             "TypeId": {"Id":2}
            },
            {"Id":3,
             "TypeId": {"Id":1}
            }
            {"Id":4,
             "TypeId": {"Id":2}
            },
            {"Id":5,
             "TypeId": {"Id":2}
            }
        ]
    }
]

So I am wondering if there is a best-practice for this. Sending the same object (Type) over and over again as a nested object in A seems quite "stupid".

Especially if I convert the JSON-string into Typescript objects.

Without any "storage/cache" logic I create the "same" object over and over again:

export class A {
    public Id: number;
    public Name: string;
    public Type: Type;

    public static fromData(data: any): A {

        var a = new A();
        a.Id = data.Id;
        a.Name = data.Name;
        a.Type = Type.fromData(data.Type);

        return a;
    }
}

export class Type {
        public Id: number;
        public Name: string;

        public static fromData(data: any) : Type {
            var type = new Type();
            type.Id = data.Id;
            type.Name = data.Name;

            return type;
        }
}

// AngularJS controller
export class AListCtrl {
    static $inject = ['$scope', '$http'];

    public As: A[] = [];

    constructor(private $scope, private $http) {
        $scope.AListCtrl = this;

        $http.get('http://localhost/api/a').success((data) => {
            var as: A[] = [];
            for (var i = 0; i < data.length; i++) {
                var aData = data[i];
                var a = A.fromData(aData);

                as.push(a);
            }

            this.As = as;
        });
    }
}



Creating different objects which represent the same Types seems just wrong. Because I work a lot with references in other languages (C#, Java, C++). Using this way of de-serializing the data and creating the objects allows no usage of references at all (maybe this is wrong in web-applications?). And I also think, generating a lot of useless objects instead of one per Type is a waste of memory and CPU time.

Quite a long post, but I hope it explains my problem well.

To summarize it: I need a best-practice for sending data from the server to a client via JSON, using the JSON-string on the client side to create objects.

like image 290
bakunin Avatar asked Feb 20 '14 15:02

bakunin


Video Answer


2 Answers

I think that you need to define the JSON representation that makes the most sense for your client application, and then make sure that the data is being sent in that format. I would create a custom serializer, either using the built-in JavaScriptConverter or possibly the one provided by Json.Net. Just using the built-in serializer doesn't seem to give ideal results.

like image 71
Greg Ferreri Avatar answered Sep 28 '22 03:09

Greg Ferreri


A good rule of thumb in API design is to craft your json response to fit your client-side needs. I am sure some REST purists would disagree but in real world applications reducing XHR requests and client side processing is preferable to adhering to a dogmatic approach to resource modeling.

Letting your database / server side object model abstractions leak into your client will end up costing you time and effort. If you serialize your data to fit your client needs then you can keep that interface even if your backend implementation changes.

like image 29
Scott Puleo Avatar answered Sep 28 '22 05:09

Scott Puleo