Hi. I have the following scheme of json responses: { "status": "success", "data": { }, "message": null}`
And HTML Codes.
Now I doing like this: $response->withJson(array('status' => 'error', 'data' => null, 'message' => 'Incorrect username or password'), 404);
or $data = array('token' => $jwtToken); return $response->withJson(array('status' => 'success', 'data' => $data, 'message' => null));
I need to copy this every 500 responses in 40 controllers. I want something elegant: $response->withSJson($data);
or for error: $response->withSJson('Lecturer not exist', 404);
We use a similar sort of response structure and we’ve implemented it by subclassing the Response class and injecting it into Slim.
So, you’d need your own response class like this:
use Psr\Http\Message\ServerRequestInterface as Request;
class MyResponse extends \Slim\Http\Response {
public function withJson($data, $status = null, $encodingOptions = 0) {
if(!isset($data['error'])) {
$data['error'] = false;
}
if(!isset($data['status'])) {
$data['status'] = $status ?: $this->getStatusCode();
}
return parent::withJson($data, $status, $encodingOptions);
}
public function withJsonData($data) {
return $this->withJson([
'data' => $data
]);
}
}
And then inject it like this (which is an altered copy of the response value that’s set by default):
$slimContainer = new \Slim\Container();
// Use our Response class instead of the default. This sets some extra values on JSON responses.
$slimContainer['response'] = function ($slimContainer) {
$headers = new Headers(['Content-Type' => 'text/html; charset=UTF-8']);
$response = new MyResponse(200, $headers);
return $response->withProtocolVersion($slimContainer->get('settings')['httpVersion']);
};
$app = new \Slim\App($slimContainer);
Of course you’ll need to update the MyResponse class to match your particular response structure.
Another way to go about is to create a base controller with a protected response method which all your controllers extends that base controller.
By doing so you call $this->res($data [ , $status]);
Good luck
That I don’t know. To me it feels like the cleanest way to go about this,
and just extends the precedent set by methods like withRedirect on the
existing Slim Response class. However, it’s possible that using the
dependency injection in this way makes the code a little vulnerable to
future changes in Slim.
You can also create a service for providing the json response and inject it into your controller, or get it from the service container (depending on how you set up your actions and controllers):
// A provider for returning the responses
class SJsonResponseProvider
{
public function withOk($response, $data, $message = null)
{
return $response->withJson(['status' => 'success', 'data' => $data, 'message' => $message]);
}
public function withError($response, $message, $statusCode)
{
return $response->withJson(['status' => 'error', 'data' => $data, 'message' => $message], $statusCode);
}
}
// add the service to the service container
$app = new \Slim\App([
// define service for the provider
'json_provider' => function() { return new SJsonResponseProvider(); }
]);
$app->get('/', function($request, $response) {
// return OK
return $this->json_provider->withOk($response, ['token'=>'1234']);
// return error
return $this->json_provider->withError($response, 'Lecturer not exist', 404);
});
Or your can use traits:
trait SJsonResponseProvidable
{
private function withJsonOk($response, $data, $message = null)
{
return $response->withJson(['status' => 'success', 'data' => $data, 'message' => $message]);
}
private function withJsonError($response, $message, $statusCode)
{
return $response->withJson(['status' => 'error', 'data' => $data, 'message' => $message], $statusCode);
}
}
class MyAction
{
// add the trait to this action
use SJsonResponseProvidable;
public function __invoke($request, $response)
{
// return OK
return $this->withJsonOk($response, ['token' => '1234']);
// return erorr
return $this->withJsonError($response, 'Lecturer not exist', 404);
}
}