Best way to represent simple catalogs (key, description)

Hello, everybody!

We are building APIs for our university. While building the JSON docs following JSON:API spec, we realized that we have a considerable amount of “catalogs” of the form {“key”: “abc”, “description”: “XYZ” }. When trying to represent a resource that has many of these key-description fields as attributes, we first tried to represent the catalogs as resources and used the relationships and included objects, but then noted that the resulting JSON document grows considerably, as below:

{
    "data": {
        "type": "student",
        "id": "studentID",
        "attributes": {
            "firstName": "First Name",
            "lastName": "Last Name",
        },
        "relationships": {
            "has-gender": { "data": { "type": "genders", "id": "M" } },
            "has-nationality": { "data": [ { "type": "nationalities", "id": "01" },
                                           { "type": "nationalities", "id": "02" } ],
            "has-status": { "data": { "type": "student-status", "id": "R" } }
        },
        "included": [
            {
                "type": "genders",
                "id": "M",
                "attributes": {
                    "description": "Male"
                }
            },
            {
                "type": "nationalities",
                "id": "01",
                "attributes": {
                    "description": "Mexican"
                }
            },
            {
                "type": "nationalities",
                "id": "02",
                "attributes": {
                   "description": "US American"
                }
            },
            {
                "type": "student-status",
                "id": "R",
                "attributes": {
                    "description": "Regular"
                }
            }
        ]
    }
}

This is for a single student representation. We then thought about including the foreign keys as attributes of the student, together with their corresponding descriptions in an object, as follows:

{
    "data": {
        "type": "student",
        "id": "studentID",
        "attributes": {
            "firstName": "First Name",
            "lastName": "Last Name",
            "gender": { "genderKey": "M", "genderDescription": "Male" },
            "nationalities": [ { "nationalityKey": "01", "nationalityDescription": "Mexican" },
                               { "nationalityKey": "02", "nationalityDescription": "US American" } ],
            "student-status": { "statusKey": "R", "statusDescription": "Regular" }
        }
    }
}

This is just an example, but we have resources that contain more than 10 attributes of this type and become very verbose when using relationships.

Is the last approach “correct”? I read in the spec that foreign keys SHOULD NOT be part of the attributes of a resource, but precisely because it says “SHOULD NOT”, and not “MUST NOT”, is that we are considering this approach.

We could define to set as attributes only the descriptions, but in some cases the consumer could need the keys to perfom some other operations.

Any comments are welcome. Thank you!

If you use a relationship like this:

"has-gender": { "data": { "type": "genders", "id": "M" } }

then you say that there exists a resource of type genders with ID "M". Is that correct? Alternatively, a gender could just be an enum attribute:

"gender": "M"

where you then have to document the known set of values for the gender attribute.

Also, is there a reason you call stuff has-xx? Seems verbose. I’d just call it gender, nationalities, and studentStatus.

I don’t know much about your domain, but I would probably represent both gender and status as enum attributes as described above. If some of these are dynamic and you actually need to have them as resources (e.g. you have a /nationalities endpoint where you can manage the known nationalities), then I’d use relationships for those. I would also primarily use relationships for anything that’s to-many (like nationalities). That makes it possible for clients to add/remove members and not just replace the complete set.

Yes, JSON:API is a bit verbose with many relationships. No way around that. The benefit is the flexibility. And keep in mind that the client code doesn’t care about the verbosity. What seems verbose to humans may actually be very small amounts of data in the grand scheme of things.