JSON endpoints 

The contract of the editing endpoints, for a client other than the one this extension ships. Everything below is enforced by the server; a client that violates it receives one of the status codes in the last section.

How they are addressed 

The endpoints are a PAGE object of their own, keyed on a page type. They answer on whichever page the edit plugin sits on, so no page has to be created for them.

Setting TypoScript constant Default
modernextbasefrontendedit.ajaxPageType plugin.tx_modernextbasefrontendedit.settings.ajaxPageType 1589

The page object renders the Extbase plugin Ajax of the extension directly, with config.disableAllHeaderCode = 1 so the body is exactly what the action produced, and config.no_cache = 1. view.formatToPageTypeMapping.json is set to the same number.

The map carries eight entries: save, saveField, addChild, removeChild, reorderChildren, setChildVisibility, uploadImage and removeImage. read is deliberately not among them. When the page type is 0 the map is empty.

The endpoints 

All of them are POST. All of them except uploadImage take a JSON object as the request body.

Endpoint Body keys Writes
read uid (optional) Nothing. Returns the caller's profile.
save uid, data, and child with childUid when a child record is addressed Every writable field of one record at once.
saveField uid, field, value, and child with childUid when a child record is addressed One named field of one record.
addChild uid, child, data One new child record, appended last.
removeChild uid, child, childUid Deletes the addressed child record.
reorderChildren uid, child, order The sorting of one collection.
setChildVisibility uid, child, childUid, hidden The hidden state of one child record.
uploadImage A multipart/form-data body — see Image upload The profile image.
removeImage uid Clears the profile image.

The value types are checked strictly, and a value of the wrong type is a 400 rather than something that is cast:

Key Type
uid, childUid A JSON integer greater than 0. A numeric string is refused.
child "address" or "email". Absent or null addresses the profile itself, which save and saveField allow and the four collection endpoints do not.
data A JSON object.
field A non-empty string naming a writable field — see Validation rules.
value A string, or null.
hidden A JSON boolean.
order A JSON array of integers greater than 0. It has to be a permutation of the whole collection: a wrong length or a repeated uid is refused before anything is written.

uid is required by every endpoint except read, and it is only ever a filter: the set of records a request may reach is resolved from the session, and a uid outside that set is answered like a uid that does not exist.

The request token 

Every writing endpoint requires a TYPO3 request token in the X-TYPO3-RequestToken header. It is a hash signed JWT bound to a nonce cookie of that browser, with the scope

modern_extbase_frontend_edit/record-save
Copied!

A token that is missing, that cannot be verified, or that carries a different scope is refused identically. The token is proof that the browser loaded a page of this site; it is not authorisation, and it does not replace the login check.

The __RequestToken body parameter TYPO3 also accepts is not usable here: it is read from the parsed request body, which is empty for a request carrying a JSON body.

read requires no token and no login. It changes nothing, and answering an anonymous caller differently from a logged-in non-owner would say which profiles exist.

The guards, in order 

For a writing endpoint with a JSON body, each check runs before any value of the request body is looked at:

Order Check Failure
1 The request method is POST. 405, with an Allow: POST header.
2 The media type is application/json. 400
3 A valid request token of the scope above was received. 403
4 A website user is logged in. 403
5 The request runs in the live workspace. 409
6 The body is empty, or a JSON object. 400
7 The addressed record is in the set the session owns. 404
8 The remaining body keys have the required types. 400
9 The submitted values satisfy the validation rules. 422

read runs steps 1, 2, 6 and 7 only. uploadImage replaces step 2 with multipart/form-data and adds a check that exactly one file was sent; its order is otherwise the same.

The response envelope 

Every response carries a JSON body and the content type application/json; charset=utf-8 — successes and failures alike.

A success is 200 and one key:

{
    "data": {}
}
Copied!

data is the whole profile as it stands after the write, not an echo of the request, and it is the same document for every endpoint — including the ones that changed a single field.

A failure carries one key as well:

{
    "errors": [
        {
            "code": 1786495903,
            "message": "Request token missing or invalid."
        }
    ]
}
Copied!

code is a TYPO3 style exception code identifying the one line that refused the request. message is written for a developer, is not localized, and never repeats a value the request carried.

A 422 uses the same key with one entry per rejected value, and those entries carry a field:

{
    "errors": [
        {
            "field": "shortname",
            "code": 1221560718,
            "message": "Enter a short name."
        }
    ]
}
Copied!

field is the name of the rejected field, or null for an error that belongs to the record rather than to one of its fields. A rejected image upload is keyed under image. The message of a validation error is localized: it comes from the label file and is already translated and substituted.

The profile document 

The object under data, and the same document the edit plugin renders into its markup:

Key Value
uid The profile uid.
shortname, firstname, lastname, bio Strings.
birthday YYYY-MM-DD, or "" for "no birthday".
hidden Boolean. Readable, and writable by no endpoint.
image null, or an object with uid (the sys_file_reference uid), fileUid (the sys_file uid), publicUrl, name, extension, mimeType, size, title, alternative, width and height.
addresses A list of objects with uid, type, line1, line2 and hidden, in their stored order.
emails A list of objects with uid, type, email and hidden, in their stored order.

Both collections contain the records the owner has hidden, marked by their hidden flag. That is what lets an owner find and publish them again.

Status codes 

Status Meaning
200 The write was performed. The body carries the resulting document.
400 The request is malformed: a wrong media type, a body that is not a JSON object, a missing or wrongly typed key, an unknown child collection, an unknown field name, or more than one uploaded file.
403 The request token is missing or invalid, or no website user is logged in. Which of the two is not distinguished.
404 The addressed record does not exist, or does not belong to the calling session. The two are deliberately indistinguishable.
405 The request method is not POST. The response carries Allow: POST.
409 A workspace is active. The request is well formed and authorised, and the state of the session is what makes it unanswerable.
422 A submitted value was rejected by a validation rule. The body names the field.