You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -13,11 +13,9 @@ import VideoDocs from '/@theme/components/VideoDocs.vue'
13
13
14
14
## What is middleware?
15
15
16
-
In simple terms, middleware is a piece of code that runs before your application runs. It can be used to perform various tasks like authentication, error handling, logging, etc. It can also help to optimize the performance of an application by caching data, compressing responses, or distributing load across multiple servers, although those are more advanced use-cases. It's a great way to keep your code clean and organized.
16
+
Middleware is a piece of code that runs before or after your application processes a request. It helps control the flow of requests and responses. For example, when a user visits a page on your app, you can use middleware can check if the user is logged in and if everything is okay, the request moves on to the next step; if not, the middleware can redirect the user.
17
17
18
-
::: tip Note
19
-
Leaf has modules that can be used to perform some of the tasks middleware can do. For example, Leaf has [Leaf Auth](/modules/auth/v/2.1/) which can be used to handle authentication, a [logger module](/docs/tooling/logging) and many more useful [modules](/modules/). This means you don't need to use middleware to perform these tasks. However, middleware can be used to perform tasks that Leaf modules don't cover.
20
-
:::
18
+
Note that Leaf has modules that offer most of these functionalities out of the box, so you might not need to write your own middleware for them.
21
19
22
20
## How does middleware work?
23
21
@@ -32,264 +30,131 @@ When a request is made to your application, Leaf will run through the middleware
32
30
link="https://www.youtube.com/embed/Hqk9yUJfRKg"
33
31
/>
34
32
35
-
## Middleware in Leaf
36
-
37
-
Leaf provides 2 interfaces for middleware: application middleware and router hooks.
38
-
39
-
- Router hooks basically hook into the runtime of the Leaf router and allow you to run code before a route/multiple routes are invoked.
40
-
- Application middleware on the other hand is a more structured way to define and use middleware in your apps. It allows you to define middleware classes as done in other frameworks like Laravel. This fits right in if you intend to build MVC applications.
41
-
42
-
## Application middleware
43
-
44
-
As mentioned above, application middleware gives you a more structured way to define and use middleware in your apps. It allows you to define middleware as classes instead of using functions.
45
-
46
-
### Defining application middleware
33
+
## Creating Middleware
47
34
48
-
Leaf provides a `Middleware` class that you can extend to define your application middleware. The `Middleware` class has a `call` method that you can override to define your middleware logic. In the `call` method, you can perform any task you want and then call `$this->next()` to pass the request to the next middleware in the stack or even return a response if you want to break the execution of your application. The example below checks if a request key is set, if it's not, the user is redirected to another route.
35
+
In Leaf, middleware are just functions that are loaded into Leaf. Here's an example of a simple middleware that logs the request methodand URI:
49
36
50
37
```php
51
-
class TestMiddleware extends Leaf\Middleware
52
-
{
53
-
public function call()
54
-
{
55
-
if (!request()->get('key')) {
56
-
return Custom::redirect('/login');
57
-
}
58
-
59
-
return $this->next();
60
-
}
38
+
$logRequest = function () {
39
+
$method = request()->method();
40
+
$uri = request()->uri();
41
+
42
+
echo "[$method] $uri\n";
61
43
}
62
44
```
63
45
64
-
One thing to note is you should always call `$this->next()`. The `$this->next()` method forwards the incoming request to the next middleware or your application if there's no other middleware.
65
-
66
-
### Using your application middleware
67
-
68
-
After defining the middleware, the next step is to tell Leaf to actually run your middleware. You can do this by calling the `use` method on the Leaf instance.
69
-
70
-
<divclass="class-mode">
46
+
To use this middleware, you can pass it to the use() method on the Leaf instance:
71
47
72
48
```php
73
-
$app = new Leaf\App();
74
-
75
-
$app->use(new TestMiddleware);
76
-
77
-
// ... your routes here
49
+
app()->use($logRequest);
78
50
```
79
51
80
-
</div>
81
-
<divclass="functional-mode">
52
+
Or you can write this together:
82
53
83
54
```php
84
-
app()->use(new TestMiddleware);
85
-
86
-
// ... your routes here
87
-
```
88
-
89
-
</div>
55
+
app()->use(function () {
56
+
$method = request()->method();
57
+
$uri = request()->uri();
90
58
91
-
## Before Route Middlewares
92
-
93
-
This is a type of router hook that runs before a particular route is invoked. It is technically just a callable/function that holds whatever code you want to execute before the route is executed. To actually create and register the before route middleware, you need to pass the function into the `before` method of the Leaf instance.
94
-
95
-
The `before` method takes 3 arguments:
96
-
97
-
- The HTTP method: This can be a single method or a pipe-separated list of methods.
98
-
- The route pattern
99
-
- The middleware function
100
-
101
-
This example below shows how to create a before route middleware that checks if a user is logged in before allowing access to the admin dashboard. Note that we're using `/admin/.*` as the route pattern. This means that the middleware will be executed for all routes that start with `/admin/`.
102
-
103
-
<divclass="class-mode">
104
-
105
-
```php
106
-
$app->before('GET|POST', '/admin/.*', function () {
107
-
if (!isset($_SESSION['user'])) {
108
-
header('location: /auth/login');
109
-
exit();
110
-
}
59
+
echo "[$method] $uri\n";
111
60
});
112
61
```
113
62
114
-
</div>
115
-
<divclass="functional-mode">
63
+
Using middleware this way will run the middleware for every request. If you only want to run the middleware for specific routes, you can pass the middleware as a route option.
116
64
117
-
```php
118
-
app()->before('GET|POST', '/admin/.*', function () {
119
-
if (!isset($_SESSION['user'])) {
120
-
header('location: /auth/login');
121
-
exit();
122
-
}
123
-
});
124
-
```
65
+
## Middleware as a route option
125
66
126
-
</div>
127
-
128
-
### Matching multiple middleware
129
-
130
-
Unlike route handling functions, more than one before route middleware is executed when more than one route match is found.
131
-
132
-
<divclass="class-mode">
67
+
Passing middleware as a route option will run the middleware only for that route or group of routes. You can pass a single middleware or an array of middleware to the middleware option.
133
68
134
69
```php
135
-
$app->before('GET|POST', '/admin/.*', function () {
136
-
if (!isset($_SESSION['user'])) {
137
-
header('location: /auth/login');
138
-
exit();
139
-
}
140
-
});
70
+
$middleware = function () {
71
+
$method = request()->method();
72
+
$uri = request()->uri();
141
73
142
-
$app->before('GET|POST', '/admin/.*', function () {
143
-
if (!isset($_SESSION['user_secret'])) {
144
-
header('location: /auth/login');
145
-
exit();
146
-
}
147
-
});
148
-
```
74
+
echo "[$method] $uri\n";
75
+
};
149
76
150
-
</div>
151
-
<divclass="functional-mode">
77
+
app()->get('/home', ['middleware' => $middleware, function () {
78
+
echo 'Home page';
79
+
}]);
152
80
153
-
```php
154
-
app()->before('GET|POST', '/admin/.*', function () {
155
-
if (!isset($_SESSION['user'])) {
156
-
header('location: /auth/login');
157
-
exit();
158
-
}
159
-
});
81
+
app()->group('/admin', ['middleware' => $middleware, function () {
82
+
app()->get('/', function () {
83
+
echo 'admin dashboard';
84
+
});
160
85
161
-
app()->before('GET|POST', '/admin/.*', function () {
162
-
if (!isset($_SESSION['user_secret'])) {
163
-
header('location: /auth/login');
164
-
exit();
165
-
}
86
+
app()->get('/users', function () {
87
+
echo 'admin users';
88
+
});
166
89
});
167
90
```
168
91
169
-
</div>
170
-
171
-
Using this same concept, you can run your middleware on every route. We call this before router middleware.
172
-
173
-
## Before Router Middlewares
92
+
This will run the $middleware function before the route handler for the /home route and all routes in the /admin group. This way, you won't have to run middleware for routes you don't need it for.
174
93
175
-
Before route middlewares are route specific. Using a general route pattern (viz. all URLs), they can become Before Router Middlewares (in other projects sometimes referred to as before app middlewares) which are always executed, no matter what the requested URL is.
94
+
## Registering Middleware
176
95
177
-
<divclass="class-mode">
96
+
It's a bit bulky to write your middleware inline every time you need it. Leaf allows you to register middleware globally so you can use it anywhere in your app.
178
97
179
98
```php
180
-
$app->before('GET', '/.*', function () {
181
-
// ... this will always be executed
182
-
});
183
-
```
99
+
app()->registerMiddleware('logRequest', function () {
100
+
$method = request()->method();
101
+
$uri = request()->uri();
184
102
185
-
</div>
186
-
<divclass="functional-mode">
187
-
188
-
```php
189
-
app()->before('GET', '/.*', function () {
190
-
// ... this will always be executed
103
+
echo "[$method] $uri\n";
191
104
});
192
105
```
193
106
194
-
</div>
195
-
196
-
As you can see, the only difference between before route and before router middleware is the route pattern.
197
-
198
-
## Middleware route option
199
-
200
-
This is a new way to quickly setup middleware for a particular route. Leaf has the before method which allows you to set a route specific middleware, but that means defining the same route twice, not to mention, you may mistake the middleware for the main route as they have the same syntax. This problem is solved by the middleware option. **If your prefer using `before`, you can always do so.**
201
-
202
-
Let's take this function which we're using as our middleware:
203
-
204
-
```php
205
-
$midfn = function () {
206
-
echo 'Home middleware';
207
-
};
208
-
```
209
-
210
-
We can use this middleware directly on our route like this:
211
-
212
-
<divclass="class-mode">
107
+
We can now use this middleware in our routes:
213
108
214
109
```php
215
-
$app->get('/home', ['middleware' => $midfn, function () {
216
-
echo 'User Home';
217
-
}]);
218
-
```
110
+
// using middleware for all routes
111
+
app()->use('logRequest');
219
112
220
-
</div>
221
-
<divclass="functional-mode">
222
-
223
-
```php
224
-
app()->get('/home', ['middleware' => $midfn, function () {
225
-
echo 'User Home';
113
+
// using middleware for a specific route
114
+
app()->get('/home', ['middleware' => 'logRequest', function () {
115
+
echo 'Home page';
226
116
}]);
227
-
```
228
117
229
-
</div>
118
+
// using middleware for a group of routes
119
+
app()->group('/admin', ['middleware' => 'logRequest', function () {
120
+
app()->get('/', function () {
121
+
echo 'admin dashboard';
122
+
});
230
123
231
-
## Named Middleware Route Options <supclass="vt-badge">New</sup>
232
-
233
-
You can name your middleware and use it on multiple routes. This is useful when you have a lot of routes that use the same middleware. You can name your middleware like this:
234
-
235
-
<divclass="class-mode">
236
-
237
-
```php
238
-
$app->registerMiddleware('home', function () {
239
-
echo 'Home middleware';
124
+
app()->get('/users', function () {
125
+
echo 'admin users';
126
+
});
240
127
});
241
-
242
-
$app->get('/home', ['middleware' => 'home', function () { ... }]);
243
-
$app->get('/home/about', ['middleware' => 'home', function () { ... }]);
244
128
```
245
129
246
-
</div>
130
+
Notice how we passed the middleware name as a string instead of the actual function. This is because we registered the middleware with a name. This makes it easier to manage middleware in your app.
247
131
248
-
<divclass="functional-mode">
249
-
250
-
```php
251
-
app()->registerMiddleware('home', function () {
252
-
echo 'Home middleware';
253
-
});
132
+
## Passing data from middleware
254
133
255
-
app()->get('/home', ['middleware' => 'home', function () { ... }]);
256
-
app()->get('/home/about', ['middleware' => 'home', function () { ... }]);
257
-
```
134
+
It is necessary in some cases to pass data from middleware to the route handler. Leaf allows you to pass data from middleware to the route handler using the `response()->next()` method.
258
135
259
-
</div>
260
-
261
-
Named middleware can also be used with route groups:
136
+
```php
137
+
app()->registerMiddleware('logRequest', function ($next) {
138
+
$method = request()->method();
139
+
$uri = request()->uri();
262
140
263
-
<divclass="class-mode">
141
+
echo "[$method] $uri\n";
264
142
265
-
```php
266
-
$app->registerMiddleware('home', function () {
267
-
echo 'Home middleware';
143
+
// pass data to the next handler
144
+
response()->next('You can pass any value here');
268
145
});
269
-
270
-
$app->group('/group', ['middleware' => 'home', function () use ($app) {
271
-
$app->get('/home', function () { ... });
272
-
$app->get('/home/about', function () { ... });
273
-
}]);
274
146
```
275
147
276
-
</div>
277
-
278
-
<divclass="functional-mode">
148
+
The data passed to the $next function will be available in the route handler:
279
149
280
150
```php
281
-
app()->registerMiddleware('home', function () {
282
-
echo 'Home middleware';
283
-
});
151
+
app()->get('/home', ['middleware' => 'logRequest', function () {
152
+
$middlewareData = request()->next();
284
153
285
-
app()->group('/group', ['middleware' => 'home', function () {
286
-
app()->get('/home', function () { ... });
287
-
app()->get('/home/about', function () { ... });
154
+
echo $middlewareData; // "You can pass any value here"
288
155
}]);
289
156
```
290
157
291
-
</div>
292
-
293
158
## Router Hooks
294
159
295
160
Hooks basically allow you to hook into Leaf router and execute a callback at a given time. For instance, you can execute a function just before Leaf fires off routes. You can also execute a callback before the main middleware executes or even after Leaf has completely executed a route.
0 commit comments