Yoksan Herlie
Yoksan Herlie

Reputation: 123

Set default JSON format response Laravel

I'm practicing to make a good RESTful API services following this guide from Google (https://google.github.io/styleguide/jsoncstyleguide.xml) for the json format response.

Is there any way to set the default JSON format for every response because in the guide said

In order to maintain a consistent interface across APIs, JSON objects should follow the structure outlined below.

object {
  string apiVersion?;
  string context?;
  string id?;
  string method?;
  object {
    string id?
  }* params?;
  object {
    string kind?;
    string fields?;
    string etag?;
    string id?;
    string lang?;
    string updated?; # date formatted RFC 3339
    boolean deleted?;
    integer currentItemCount?;
    integer itemsPerPage?;
    integer startIndex?;
    integer totalItems?;
    integer pageIndex?;
    integer totalPages?;
    string pageLinkTemplate /^https?:/ ?;
    object {}* next?;
    string nextLink?;
    object {}* previous?;
    string previousLink?;
    object {}* self?;
    string selfLink?;
    object {}* edit?;
    string editLink?;
    array [
      object {}*;
    ] items?;
  }* data?;
  object {
    integer code?;
    string message?;
    array [
      object {
        string domain?;
        string reason?;
        string message?;
        string location?;
        string locationType?;
        string extendedHelp?;
        string sendReport?;
      }*;
    ] errors?;
  }* error?;
}*;

I'm practicing with Laravel 5.4. Should I just make a trait and use make own JSON response format? Because, it's so cumbersome having to write that kind of response every time you return a JSON response.

Upvotes: 1

Views: 6695

Answers (4)

Gochi Siyan
Gochi Siyan

Reputation: 29

In Laravel 11, you can use middleware to intercept the response object.

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ResponseAPI
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        if (in_array($response->status(), [200, 201, 404, 401, 422])) {
            $response->header('Content-Type', 'application/json');
        }

        return $response;
    }
}

Since Kernel.php is no longer available in Laravel 11, you can add the middleware in bootstrap/app.php.

<?php

use App\Http\Middleware\ResponseAPI;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        // web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(ResponseAPI::class); // Your costum middleware
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })
    ->create();

Since the middleware is applied globally, all your response should be returned in json format.

Upvotes: 0

Sean
Sean

Reputation: 480

You can add middleware to force a JSON response by setting the "accepts" header on the incoming request. Include that middleware in HttpKernel's $middlewareGroups['api'] to cover all api routes. This is a Laravel ^7.0 solution.

<?php
# app/Http/Middleware/JsonResponse.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class JsonResponse {

    /**
     * Set 'Accept' header to force a JSON response for API routes.
     *
     * @param  Request  $request
     * @param  Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {    
        $request->header->set('accept', 'application/json');
        return $response;
    }

}

--

<?php
# app/Http/Kernel.php
.
.
.
protected $middlewareGroups = [
    'web' => [...],
    'api' => [
        'throttle:60,1',
        ApiJsonResponse::class
    ]
];

Credit to Alfredo EM for leading me to this solution.

Upvotes: 0

Alfredo EM
Alfredo EM

Reputation: 2069

You can use a Middleware to intercept the response object and format it as you like, for example I usually use this to append headers in the response:

<?php
# app/Http/Middleware/ResponseAPI.php

namespace App\Http\Middleware;

use Closure;

class ResponseAPI {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        $response = $next($request);

        if (in_array($response->status(), [200, 201, 404, 401, 422])) {
            $response->header('Content-Type', 'application/json');
        }

        return $response;
    }

}

--

<?php
# app/Http/Kernel.php
.
.
.
protected $routeMiddleware = [
  # others middlewares
  'api.response' => \App\Http\Middleware\ResponseAPI::class
];

--

<?php
# app/Http/routes.php

$app->group(['prefix' => 'api/v1', 'middleware' => ['api.response']], function($app) {
    # all routes
});

Upvotes: 5

Related Questions