Skip to content

Commit cf981cd

Browse files
refactor(dev): revise OCS json serialization of empty values section
Signed-off-by: Josh <josh.t.richards@gmail.com>
1 parent 2f189a0 commit cf981cd

1 file changed

Lines changed: 63 additions & 41 deletions

File tree

developer_manual/client_apis/OCS/ocs-openapi.rst

Lines changed: 63 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -95,61 +95,83 @@ For details take a look at :ref:`OCS <ocscontroller>`.
9595
}
9696
}
9797
98-
PREFER to use ``null`` to represent empty data
99-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
98+
CAREFULLY handle empty values in JSON Responses
99+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100100

101-
When an endpoint conceptually returns an object, prefer ``null`` to represent "no data".
101+
When defining API responses, it’s important to make explicit whether an empty value should be ``null``, an empty object (``{}``), or an empty array (``[]``) in the resulting JSON. The PHP type you return determines this, and using the wrong one can easily lead to confusing or inconsistent results for your API consumers.
102102

103-
There is a problem with PHP and arrays that get converted to JSON.
104-
JSON has lists and objects while PHP only has arrays.
105-
If you were to return an empty array in PHP it will always turn into ``[]`` in JSON.
106-
This is not a problem for endpoints that always return lists, but most endpoints return a single JSON object.
107-
For those endpoints returning ``[]`` in PHP is a problem because the consumer will either get ``[]`` or ``{...}`` which is hard to handle.
103+
.. note::
108104

109-
If you are not able to use ``null`` for whatever reason, use ``new \stdClass()`` instead.
110-
It will get correctly converted into ``{}`` in the JSON response on Nextcloud 28 and later.
105+
In PHP, ``null``, ``[]``, and ``new \stdClass()`` are distinct types and will be serialized to different values in JSON. This is especially important for OpenAPI consumers, which often expect a consistent type.
111106

112-
If you are working with an existing API where you can not break compatibility, you can also type the result as ``list<empty>``.
107+
Here is how PHP values are serialized to JSON:
108+
109+
+-------------------+--------------------+
110+
| PHP Value | JSON Output |
111+
+===================+====================+
112+
| null | null |
113+
+-------------------+--------------------+
114+
| new \stdClass() | {} |
115+
+-------------------+--------------------+
116+
| [] | [] |
117+
+-------------------+--------------------+
118+
119+
- Use ``null`` to indicate that a value is explicitly absent. This should be preferred for most “empty” responses.
120+
- Use ``new \stdClass()`` **if and only if** the client expects an empty object (`{}`) rather than `null`. This is sometimes required by schema contracts that always expect an object shape, even if empty.
121+
122+
.. important::
123+
124+
Returning ``new \stdClass()`` as an API response requires at least Nextcloud 28 to reliably serialize to ``{}``.
125+
126+
- **Avoid returning ``[]``** for endpoints expected to yield a JSON object, as this will serialize to a JSON array (`[]`), causing downstream consumers to deal with unpredictable types.
127+
128+
If you are modifying or extending existing APIs and are unable to use ``null`` or ``\stdClass()`` without breaking backward compatibility, you may type the result as ``list<empty>`` to signal an empty array is expected.
113129

114130
.. collapse:: Examples
115131

116132
.. code-block:: php
117-
:caption: Bad
133+
:caption: Incorrect (returns empty array instead of empty object or null)
118134
119-
/**
120-
* @return DataResponse<Http::STATUS_OK, array, array{}>
121-
*/
122-
public function someControllerMethod() {
123-
...
124-
return new DataResponse([]);
125-
}
135+
/**
136+
* @return DataResponse<Http::STATUS_OK, array, array{}>
137+
*/
138+
public function someControllerMethod() {
139+
// ...
140+
return new DataResponse([]);
141+
}
126142
127143
.. code-block:: php
128-
:caption: Good
144+
:caption: Correct (empty data as null)
129145
130-
/**
131-
* @return DataResponse<Http::STATUS_OK, null, array{}>
132-
*/
133-
public function someControllerMethod() {
134-
...
135-
return new DataResponse(null);
136-
}
146+
/**
147+
* @return DataResponse<Http::STATUS_OK, null, array{}>
148+
*/
149+
public function someControllerMethod() {
150+
// ...
151+
return new DataResponse(null); // Serializes to: null in JSON
152+
}
137153
138-
/**
139-
* @return DataResponse<Http::STATUS_OK, \stdClass, array{}>
140-
*/
141-
public function someControllerMethod() {
142-
...
143-
return new DataResponse(new \stdClass());
144-
}
154+
.. code-block:: php
155+
:caption: Correct (explicit empty object)
145156
146-
/**
147-
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
148-
*/
149-
public function someControllerMethod() {
150-
...
151-
return new DataResponse([]);
152-
}
157+
/**
158+
* @return DataResponse<Http::STATUS_OK, \stdClass, array{}>
159+
*/
160+
public function someControllerMethod() {
161+
// ...
162+
return new DataResponse(new \stdClass()); // Serializes to: {} in JSON
163+
}
164+
165+
.. code-block:: php
166+
:caption: For legacy or compatibility cases (explicit empty list)
167+
168+
/**
169+
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
170+
*/
171+
public function someControllerMethod() {
172+
// ...
173+
return new DataResponse([]); // Serializes to: [] in JSON
174+
}
153175
154176
DO use the same data structures for the same group of responses
155177
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)