Middleware
ForceJsonApiResponse
Forces all responses to use the application/vnd.api+json content type, as required by the JSON:API spec.
// routes/api.php
use BlueBeetle\ApiToolkit\Http\Middleware\ForceJsonApiResponse;
Route::middleware([ForceJsonApiResponse::class])->group(function () {
Route::apiResource('products', ProductController::class);
});
This ensures every response from your API routes has the correct content type header, even for error responses.
ETag
Adds automatic ETag headers to GET responses and returns 304 Not Modified when the client sends a matching If-None-Match header. This reduces bandwidth for API consumers that cache responses.
// routes/api.php
use BlueBeetle\ApiToolkit\Http\Middleware\ETag;
Route::middleware([ETag::class])->group(function () {
Route::apiResource('products', ProductController::class);
});
How It Works
- The middleware generates an ETag from the response content (MD5 hash)
- The ETag is added to the response headers
- On subsequent requests, if the client sends
If-None-Matchwith the same ETag, a304 Not Modifiedresponse is returned with an empty body
When It Applies
The middleware only processes responses that meet all of these conditions:
- The request method is safe (GET, HEAD)
- The response status is successful (2xx)
- The response body is not empty
POST, PUT, PATCH, DELETE requests and error responses are passed through unchanged.
Example Flow
# First request - full response with ETag
GET /api/products
→ 200 OK
→ ETag: "a1b2c3d4..."
→ {"data": [...]}
# Second request - client sends cached ETag
GET /api/products
If-None-Match: "a1b2c3d4..."
→ 304 Not Modified
→ (empty body)
# Data changed - ETag no longer matches
GET /api/products
If-None-Match: "a1b2c3d4..."
→ 200 OK
→ ETag: "e5f6g7h8..."
→ {"data": [...]}