skip to Main Content

Consider the scenario where we create a record for capturing a JSON payload. (application/json content type)
Is there any benefit of using a closed record with a JSON type rest descriptor over an open record?

Since JSON allows any primitive types and their derived array/record (object) assignment, and the record is only used for capturing a JSON payload, restricting it as a closed record seems redundant. (Only a few types like XML, query (SQL) will be restricted which cannot pass from application/json content)

E.g.:

type Person record {|
    string name;
    int age;
    json...;
|}

vs.

type Person record {
    string name;
    int age;
}

2

Answers


  1. type Person record {|
        string name;
        int age;
        json...;
    |};
    
    type Person2 record {
        string name;
        int age;
    };
    
    public function main() {
        Person p = {name: "John", age: 30, "id": 1};
        Person2 p2 = {name: "John", age: 30, "id": 1};
    
        json id = p["id"]; // no needs to cast
        json id2 = <json> p2["id"]; // If you need to derive the id field as a json, you have to cast it
    }
    

    Please consider the above code.

    In here with the second type definition (open record), when you accessing the id field, you have to cast it into a json.

    In that kind of scenario it will be better to use closed record with rest descriptive.

    Login or Signup to reply.
  2. Both of these are open records.

    type Person record {
        string name;
        int age;
    }
    

    is equivalent to

    type Person record {|
        string name;
        int age;
        anydata...;
    |}
    

    So the difference here is a rest descriptor of json vs anydata.

    Having a more specific type is a better reflection of the possible values. Without the explicit rest descriptor (json...) the type says (additional/rest) field values can be anydata (therefore, can be table and xml too), but that isn’t the case here.

    With just response data binding to extract only the specified fields, it wouldn’t make much of a difference either way. But, if you need to use Person in a context that expects a json value, if you open it with anydata, you’ll have to do an extra conversion, which can be expensive.

    E.g.,

    import ballerina/http;
    
    type E1 record {
        int id;
        string name;
    };
    
    type E2 record {|
        int id;
        string name;
        json...;
    |};
    
    // http:Request.setJsonPayload expects a `json` value as the argument
    
    function f1(http:Request req, E1 e1) {
        req.setJsonPayload(e1); // error
        req.setJsonPayload(e1.toJson()); // OK, but needs a conversion
    }
    
    function f2(http:Request req, E2 e2) {
        req.setJsonPayload(e2); // OK, without a conversion
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search