The approach you've described for reusing Inertia controllers for an API by using a middleware to manipulate the response is quite clever. It allows you to maintain a single source of truth for your data handling logic, which can be beneficial in smaller projects where the overhead of maintaining separate controllers for web and API routes is not justified.
Here are some thoughts on your approach:
-
Maintainability: While this approach can save time initially, it may lead to confusion for developers who are new to the project or for those who expect a clear separation between API and web controllers. It's important to document this behavior clearly.
-
Custom Actions: For custom actions that do not fit the standard resource controller methods, you might need to adjust the middleware to handle different response structures. This could add complexity to your middleware logic.
-
Middleware Parameter: The idea of adding a "pick" parameter to the middleware to specify which part of the response to return is interesting. It would allow for more flexibility and could be implemented using dot notation to access nested data.
-
Performance: There might be a slight performance overhead due to the additional processing in the middleware. However, this is likely negligible and would not be a concern for most applications.
-
Testing: Ensure that your API endpoints are thoroughly tested, as the middleware adds an extra layer that transforms the response. This is crucial to ensure that the API behaves as expected.
-
Versioning: Since you're removing the
versionkey from the response, make sure that this does not interfere with Inertia's built-in mechanism for asset versioning and page reloads when assets change.
Here's an example of how you might implement the "pick" parameter in your middleware:
class InertiaToApiResponse
{
public function handle(Request $request, Closure $next, $pick = null): Response
{
// forces inertia to create json response
$request->headers->set('X-Inertia', true);
// get response
$response = $next($request);
if ($response instanceof JsonResponse) {
$data = $response->getData(true);
// If a "pick" parameter is provided, only return that part of the data
if ($pick) {
$data = Arr::get($data, $pick);
} else {
// modify data and remove component
Arr::forget($data, 'component');
// set move props to data
$data['data'] = $data['props'];
Arr::forget($data, 'props');
// forget version
Arr::forget($data, 'version');
}
$response->setData($data);
// remove X-Inertia header to not trigger version change response of inertia middleware
$response->headers->remove('X-Inertia');
}
return $response;
}
}
To use the "pick" parameter, you would modify your route definition like this:
Route::middleware('inertia.to.api.response:posts.data')->group(function () {
Route::apiResource('posts', \App\Http\Controllers\PostController::class);
});
In conclusion, your approach is not stupid at all; it's a pragmatic solution for certain types of projects. However, it's important to weigh the benefits against potential drawbacks such as maintainability and clarity. If you decide to go this route, make sure it's well-documented and consider the points mentioned above.