Only Allow content type json on POST requests in laravel

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Only Allow Content Type JSON on POST Requests in Laravel: Mastering API Content Negotiation

Building robust APIs requires strict control over the data formats you accept. When you are designing a RESTful interface, ensuring that your endpoints only process the data types they expect—in this case, exclusively application/json for POST requests—is crucial for security, predictability, and maintainability.

You asked if there is a better way than simple middleware checks to enforce this restriction. While basic checks are possible, the most elegant and idiomatic solution in the Laravel ecosystem involves leveraging the framework's built-in request handling capabilities, specifically through custom middleware that interacts with HTTP content negotiation principles.

The Challenge of Content Negotiation

When a client sends an HTTP request, it includes headers that describe the data being sent (Content-Type) and the data the client is willing to accept (Accept). For strict API design, we need to enforce that the incoming payload matches our expected format before hitting the controller logic. Simply checking the Content-Type header within a standard middleware is functional, but often less expressive than using established HTTP negotiation patterns.

The goal here is not just to block bad requests, but to return the semantically correct HTTP error code—the 406 'Not Acceptable'—which clearly signals to the client that the server cannot produce the requested representation given the constraints.

The Recommended Solution: Custom Content Negotiation Middleware

Instead of scattering this logic across many routes or complex controllers, we should centralize this validation within a custom middleware layer. This keeps your route definitions clean and ensures consistent enforcement across your entire API.

We can create a middleware that inspects the Content-Type header for POST requests. If it is not exactly application/json, we immediately halt the request processing and return the appropriate error response.

Step 1: Creating the Middleware

Let's define a simple middleware to handle this specific requirement. This logic will reside in a separate file, keeping our route definitions clean, which aligns with good architectural practices often emphasized by teams building scalable applications on platforms like Laravel.

// app/Http/Middleware/JsonContentTypeMiddleware.php

namespace App\Http\Middleware;

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

class JsonContentTypeMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        // Check if the request method is POST
        if ($request->isMethod('POST')) {

            // Check the Content-Type header
            $contentType = $request->header('Content-Type');

            // Only allow application/json
            if ($contentType !== 'application/json') {
                // Return 406 Not Acceptable if the content type is invalid for a POST request
                return response()->json([
                    'message' => 'Unsupported Media Type. Only application/json is allowed for POST requests.'
                ], 406);
            }
        }

        // If the check passes, proceed to the next layer (controller)
        return $next($request);
    }
}

Step 2: Registering and Applying the Middleware

Next, you must register this middleware in your app/Http/Kernel.php file so Laravel knows about it. Then, apply it globally or specifically to your API routes.

In app/Http/Kernel.php, add the new middleware to the $middlewareAliases array:

protected $middlewareAliases = [
    // ... other aliases
    'json.check' => \App\Http\Middleware\JsonContentTypeMiddleware::class,
];

Finally, apply it to your API routes:

// routes/api.php

Route::middleware('json.check')->post('/items', function (Request $request) {
    // This code only executes if the Content-Type header was 'application/json'
    $data = $request->json()->all();
    // ... your logic here
})->name('api.items.store');

Conclusion: Embracing Laravel's Request Pipeline

The key takeaway is that while you could implement this check manually, leveraging Laravel’s request pipeline via custom middleware provides a cleaner, more maintainable, and framework-aware solution. It properly utilizes HTTP concepts like content negotiation to enforce strict API contracts.

When building complex systems on Laravel, think about where your validation logic belongs. By encapsulating format enforcement in dedicated middleware, you ensure that every endpoint adheres to the same strict rules, making your API more predictable and robust. This approach ensures that only well-formed application/json data ever reaches your business logic, significantly improving the security posture of your application.