Mit Jackson an der Antwort sparen

“Perfektion ist nicht dann erreicht, wenn es nichts mehr hinzuzufügen gibt, sondern wenn man nichts mehr weglassen kann.”

Antoine de Saint-Exupéry

Eine REST API mit Spring Boot ist schnell einsatzbereit, aber im Betrieb produziert die Schnittstelle häufig eine Menge unnötiger Daten, die vom Server zurückgeliefert werden.

Lösungsmöglichkeiten gibt es dabei viele. Es kann der Einsatz von Jackson Views in Betracht gezogen werden. Es können aber auch diverse Varianten von Rückgabe Objekten modeliert werden,mit sehr wenigen Attributen für Listen, einigen Attributen für normale Übersichten oder allen Attributen für Detailangaben.

In der folgenden Beispiel-Antwort sind nur die Links, der Name und die Adresse der Einrichtung mit interessanten Daten gefüllt. Die restlichen Daten müssen nicht in die Antwort aufgenommen werden.

{
    "facility": {
        "name": "Beispiel Einrichtung",
        "description": null,
        "concept": "",
        "closeDays": [],
        "status": 0,
        "image": null,
        "hasHolidays": false,
        "address": {
            "street": "Allee",
            "number": "44",
            "plz": "99997",
            "city": "Gemeinde"
        }
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/1/facilities/3"
        },
        "address": {
            "href": "http://localhost:8080/api/1/facilities/3/address"
        },
        "organisation": {
            "href": "http://localhost:8080/api/1/organisation/1"
        }
    }
}

Dieses Problem ist mit den oben angeführten Möglichkeiten nicht lösbar. Aber Spring Boot liefert dafür eine sehr einfach Lösung mit Hilfe von Jackson und seinem @JsonInclude Mechanismus. Man kann den Mechanismus für jede einzelne Antwort konfigurieren oder global über eine Spring Boot Property aktivieren.

spring.jackson.default-property-inclusion=non_null

Mit dem Wert non_null entfernt Jackson alle Attribute aus der Antwort die einen null Wert enthalten. Ein Client der ein gesuchtes Attribut nicht findet, kann davon ausgehen, dass es leer ist. Mit dieser Einstellung erhalten wir.

{
    "facility": {
        "name": "Beispiel Einrichtung",
        "concept": "",
        "closeDays": [],
        "status": 0;
        "hasHolidays": false,
        "address": {
            "street": "Allee",
            "number": "44",
            "plz": "99997",
            "city": "Gemeinde"
        }
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/1/facilities/3"
        },
        "address": {
            "href": "http://localhost:8080/api/1/facilities/3/address"
        },
        "organisation": {
            "href": "http://localhost:8080/api/1/organisation/1"
        }
    }
}

Es gibt aber noch zwei weitere Einstellungen. Die nächste nennt sich non_empty und sorgt dafür, dass auch leere Listen und leere Strings nicht übertragen werden.

{
    "facility": {
        "name": "Beispiel Einrichtung",
        "status": 0;
        "hasHolidays": false,
        "address": {
            "street": "Allee",
            "number": "44",
            "plz": "99997",
            "city": "Gemeinde"
        }
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/1/facilities/3"
        },
        "address": {
            "href": "http://localhost:8080/api/1/facilities/3/address"
        },
        "organisation": {
            "href": "http://localhost:8080/api/1/organisation/1"
        }
    }
}

Die letzte Einstellung ist non_default und diese wirft dann auch noch Attribute aus der Antwort, die den Default Value für den entsprechenden Datentyp enthalten. Das sind u.a. false für Boolean Attribute und 0 für numerische Attribute.

{
    "facility": {
        "name": "Beispiel Einrichtung",
        "address": {
            "street": "Allee",
            "number": "44",
            "plz": "99997",
            "city": "Gemeinde"
        }
    },
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/1/facilities/3"
        },
        "address": {
            "href": "http://localhost:8080/api/1/facilities/3/address"
        },
        "organisation": {
            "href": "http://localhost:8080/api/1/organisation/1"
        }
    }
}

In diesem Beispiel sind es zwar nur ein paar Zeilen (13% in Bytes) die eingespart werden, aber Kleinvieh macht auch Mist.