Skip to content

Commit 8226ee4

Browse files
Redirect back when an Inertia response is empty (customizable) (#350)
* Auto redirect back for no-response Inertia reqs. * WIP
1 parent 6a050ce commit 8226ee4

File tree

4 files changed

+110
-28
lines changed

4 files changed

+110
-28
lines changed

src/Middleware.php

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Closure;
66
use Illuminate\Http\Request;
7+
use Illuminate\Support\Facades\Redirect;
78
use Symfony\Component\HttpFoundation\Response;
89

910
class Middleware
@@ -82,57 +83,57 @@ public function handle(Request $request, Closure $next)
8283
});
8384

8485
Inertia::share($this->share($request));
85-
8686
Inertia::setRootView($this->rootView($request));
8787

8888
$response = $next($request);
89-
$response = $this->checkVersion($request, $response);
9089

91-
return $this->changeRedirectCode($request, $response);
90+
if (! $request->header('X-Inertia')) {
91+
return $response;
92+
}
93+
94+
if ($request->method() === 'GET' && $request->header('X-Inertia-Version', '') !== Inertia::getVersion()) {
95+
$response = $this->onVersionChange($request, $response);
96+
}
97+
98+
if ($response->isOk() && empty($response->getContent())) {
99+
$response = $this->onEmptyResponse($request, $response);
100+
}
101+
102+
if ($response->getStatusCode() === 302 && in_array($request->method(), ['PUT', 'PATCH', 'DELETE'])) {
103+
$response->setStatusCode(303);
104+
}
105+
106+
return $response;
92107
}
93108

94109
/**
95-
* In the event that the assets change, initiate a
96-
* client-side location visit to force an update.
110+
* Determines what to do when an Inertia action returned with no response.
111+
* By default, we'll redirect the user back to where they came from.
97112
*
98113
* @param Request $request
99114
* @param Response $response
100115
* @return Response
101116
*/
102-
public function checkVersion(Request $request, Response $response)
117+
public function onEmptyResponse(Request $request, Response $response): Response
103118
{
104-
if ($request->header('X-Inertia') &&
105-
$request->method() === 'GET' &&
106-
$request->header('X-Inertia-Version', '') !== Inertia::getVersion()
107-
) {
108-
if ($request->hasSession()) {
109-
$request->session()->reflash();
110-
}
111-
112-
return Inertia::location($request->fullUrl());
113-
}
114-
115-
return $response;
119+
return Redirect::back();
116120
}
117121

118122
/**
119-
* Changes the status code during redirects, ensuring they are made as
120-
* GET requests, preventing "MethodNotAllowedHttpException" errors.
123+
* Determines what to do when the Inertia asset version has changed.
124+
* By default, we'll initiate a client-side location visit to force an update.
121125
*
122126
* @param Request $request
123127
* @param Response $response
124128
* @return Response
125129
*/
126-
public function changeRedirectCode(Request $request, Response $response)
130+
public function onVersionChange(Request $request, Response $response): Response
127131
{
128-
if ($request->header('X-Inertia') &&
129-
$response->getStatusCode() === 302 &&
130-
in_array($request->method(), ['PUT', 'PATCH', 'DELETE'])
131-
) {
132-
$response->setStatusCode(303);
132+
if ($request->hasSession()) {
133+
$request->session()->reflash();
133134
}
134135

135-
return $response;
136+
return Inertia::location($request->fullUrl());
136137
}
137138

138139
/**
@@ -142,7 +143,7 @@ public function changeRedirectCode(Request $request, Response $response)
142143
* @param Request $request
143144
* @return object
144145
*/
145-
public function resolveValidationErrors(Request $request)
146+
protected function resolveValidationErrors(Request $request)
146147
{
147148
if (! $request->session()->has('errors')) {
148149
return (object) [];

stubs/middleware.stub

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,17 @@ class {{ class }} extends Middleware
4040
//
4141
]);
4242
}
43+
44+
/**
45+
* Determines what to do when an Inertia action returned with no response.
46+
* By default, we'll redirect the user back to where they came from.
47+
*
48+
* @param Request $request
49+
* @param Response $response
50+
* @return Response
51+
*/
52+
public function onEmptyResponse(Request $request, Response $response): Response
53+
{
54+
return parent::onEmptyResponse($request, $response);
55+
}
4356
}

tests/MiddlewareTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,60 @@
1414

1515
class MiddlewareTest extends TestCase
1616
{
17+
public function test_no_response_value_by_default_means_automatically_redirecting_back_for_inertia_requests(): void
18+
{
19+
$fooCalled = false;
20+
Route::middleware(Middleware::class)->put('/', function () use (&$fooCalled) {
21+
$fooCalled = true;
22+
});
23+
24+
$response = $this
25+
->from('/foo')
26+
->put('/', [], [
27+
'X-Inertia' => 'true',
28+
'Content-Type' => 'application/json',
29+
]);
30+
31+
$response->assertRedirect('/foo');
32+
$response->assertStatus(303);
33+
$this->assertTrue($fooCalled);
34+
}
35+
36+
public function test_no_response_value_can_be_customized_by_overriding_the_middleware_method(): void
37+
{
38+
Route::middleware(ExampleMiddleware::class)->get('/', function () {
39+
// Do nothing..
40+
});
41+
42+
$this->expectException(\LogicException::class);
43+
$this->expectExceptionMessage('An empty Inertia response was returned.');
44+
45+
$this
46+
->withoutExceptionHandling()
47+
->from('/foo')
48+
->get('/', [
49+
'X-Inertia' => 'true',
50+
'Content-Type' => 'application/json',
51+
]);
52+
}
53+
54+
public function test_no_response_means_no_response_for_non_inertia_requests(): void
55+
{
56+
$fooCalled = false;
57+
Route::middleware(Middleware::class)->put('/', function () use (&$fooCalled) {
58+
$fooCalled = true;
59+
});
60+
61+
$response = $this
62+
->from('/foo')
63+
->put('/', [], [
64+
'Content-Type' => 'application/json',
65+
]);
66+
67+
$response->assertNoContent(200);
68+
$this->assertTrue($fooCalled);
69+
}
70+
1771
public function test_the_version_is_optional(): void
1872
{
1973
$this->prepareMockEndpoint();

tests/Stubs/ExampleMiddleware.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Http\Request;
66
use Inertia\Middleware;
7+
use Symfony\Component\HttpFoundation\Response;
78

89
class ExampleMiddleware extends Middleware
910
{
@@ -48,4 +49,17 @@ public function share(Request $request): array
4849
{
4950
return array_merge(parent::share($request), $this->shared);
5051
}
52+
53+
/**
54+
* Determines what to do when an Inertia action returned with no response.
55+
* By default, we'll redirect the user back to where they came from.
56+
*
57+
* @param Request $request
58+
* @param Response $response
59+
* @return Response
60+
*/
61+
public function onEmptyResponse(Request $request, Response $response): Response
62+
{
63+
throw new \LogicException('An empty Inertia response was returned.');
64+
}
5165
}

0 commit comments

Comments
 (0)