Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow bypassing content negotiation during API responses. #2904

Merged
merged 2 commits into from
Apr 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions system/API/ResponseTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
*/
trait ResponseTrait
{

/**
* Allows child classes to override the
* status code that is used in their API.
Expand Down Expand Up @@ -95,8 +94,11 @@ trait ResponseTrait
];

/**
* How to format the response data.
* Either 'json' or 'xml'. If blank will be
* determine through content negotiation.
*
* @var string the representation format to return resource data in (json/xml)
* @var string
*/
protected $format = 'json';

Expand Down Expand Up @@ -384,17 +386,14 @@ protected function format($data = null)
return $data;
}

// Determine correct response type through content negotiation
$config = new Format();
$format = "application/$this->format";

if (! in_array($this->format, ['json', 'xml']))
// Determine correct response type through content negotiation if not explicitly declared
if (empty($this->format) || ! in_array($this->format, ['json', 'xml']))
{
$format = $this->request->negotiate('media', $config->supportedResponseFormats, false);
}
else
{
$format = "application/$this->format";
}

$this->response->setContentType($format);

Expand All @@ -415,4 +414,17 @@ protected function format($data = null)
return $this->formatter->format($data);
}

/**
* Sets the format the response should be in.
*
* @param string $format
*
* @return $this
*/
public function setResponseFormat(string $format = null)
{
$this->format = strtolower($format);

return $this;
}
}
15 changes: 15 additions & 0 deletions tests/system/API/ResponseTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -502,4 +502,19 @@ public function __construct(&$request, &$response)
$this->assertStringStartsWith(config('Format')->supportedResponseFormats[0], $response->getHeaderLine('Content-Type'));
}

public function testResponseFormat()
{
$data = ['foo' => 'something'];

$controller = $this->makeController();
$controller->setResponseFormat('json');
$controller->respond($data, 201);

$this->assertStringStartsWith('application/json', $this->response->getHeaderLine('Content-Type'));

$controller->setResponseFormat('xml');
$controller->respond($data, 201);

$this->assertStringStartsWith('application/xml', $this->response->getHeaderLine('Content-Type'));
}
}
18 changes: 15 additions & 3 deletions user_guide_src/source/outgoing/api_responses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ When you pass your data in any of these methods, they will determine the data ty
the following criteria:

* If $data is a string, it will be treated as HTML to send back to the client.
* If $data is an array, it will try to negotiate the content type with what the client asked for, defaulting to JSON
* If $data is an array, it will be formatted according to the controller's ``$this->format`` value. If that is empty
it will try to negotiate the content type with what the client asked for, defaulting to JSON
if nothing else has been specified within Config\API.php, the ``$supportedResponseFormats`` property.

To define the formatter that is used, edit **Config/Format.php**. The ``$supportedResponseFormats`` contains a list of
Expand Down Expand Up @@ -104,6 +105,17 @@ JSON data will be sent back to the client.

Class Reference
***************
.. php:method:: setResponseFormat($format)

:param string $format The type of response to return, either ``json`` or ``xml``

This defines the format to be used when formatting arrays in responses. If you provide a ``null`` value for
``$format``, it will be automatically determined through content negotiation.

::

return $this->setResponseFormat('json')->respond(['error' => false]);


.. php:method:: respond($data[, $statusCode=200[, $message='']])

Expand Down Expand Up @@ -186,13 +198,13 @@ Class Reference
:param string $message: A custom "reason" message to return.
:returns: The value of the Response object's send() method.

Sets the appropriate status code to use when a command was successfully executed by the server but there is no
Sets the appropriate status code to use when a command was successfully executed by the server but there is no
meaningful reply to send back to the client, typically 204.

::

sleep(1);
return $this->respondNoContent();
return $this->respondNoContent();

.. php:method:: failUnauthorized(string $description = 'Unauthorized'[, string $code=null[, string $message = '']])

Expand Down