jsonrecordballerina

Is there any advantage of using a closed record with a rest descriptor over an open record?


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;
}

Solution

  • 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
    }