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
Copy file name to clipboardExpand all lines: README.md
+151Lines changed: 151 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -47,6 +47,153 @@ Create a production build which includes a `DockerFile` so that you can deploy a
47
47
dart_frog build
48
48
```
49
49
50
+
## Routes 🚏
51
+
52
+
In Dart Frog, a route consists of an `onRequest` function (called a route handler) exported from a `.dart` file in the `routes` directory. Each endpoint is associated with a routes file based on its file name. Files named, `index.dart` will correspond to a `/` endpoint.
53
+
54
+
For example, if you create `routes/hello.dart` that exports an `onRequest` method like below, it will be accessible at `/hello`.
55
+
56
+
```dart
57
+
import 'package:dart_frog/dart_frog.dart';
58
+
59
+
Response onRequest(RequestContext context) {
60
+
return Response(body: 'Hello World');
61
+
}
62
+
```
63
+
64
+
All route handlers have access to a `RequestContext` which can be used to access the incoming request as well as dependencies provided to the request context (see middleware).
65
+
66
+
```dart
67
+
import 'package:dart_frog/dart_frog.dart';
68
+
69
+
Response onRequest(RequestContext context) {
70
+
// Access the incoming request.
71
+
final request = context.request;
72
+
73
+
// Return a response.
74
+
return Response(body: 'Hello World');
75
+
}
76
+
```
77
+
78
+
Route handlers can be synchronous or asynchronous. To convert the above route handlers to async, we just need to update the return type from `Response` to `Future<Response>`. We can add the `async` keyword in order to `await` futures within our handler before returning a `Response`.
Dart Frog supports dynamic routes. For example, if you create a file called `routes/posts/<id>.dart`, then it will be accessible at `/posts/1`, `/posts/2`, etc.
Middleware in Dart Frog allows you to execute code before and after a request is processed. You can modify the inbound request and outbound responses by adding headers, provide dependencies, and more!
104
+
105
+
In Dart Frog, a piece of middleware consists of a `middleware` function exported from a `_middleware.dart` file within a subdirectory of the `routes` folder. There can only ever be once piece of middleware per route directory with `routes/_middleware.dart` being middleware that is executed for all inbound requests.
106
+
107
+
```dart
108
+
import 'package:dart_frog/dart_frog.dart';
109
+
110
+
Handler middleware(Handler handler) {
111
+
return (context) async {
112
+
// Execute code before request is handled.
113
+
114
+
// Forward the request to the respective handler.
115
+
final response = await handler(context);
116
+
117
+
// Execute code after request is handled.
118
+
119
+
// Return a response.
120
+
return response;
121
+
};
122
+
}
123
+
```
124
+
125
+
We can chain built-in middleware, such as the `requestLogger` middleware via the `use` API. For example, if we create `routes/_middleware.dart` with the following contents, we will automatically log all requests to our server.
126
+
127
+
```dart
128
+
import 'package:dart_frog/dart_frog.dart';
129
+
130
+
Handler middleware(Handler handler) {
131
+
return handler.use(requestLogger());
132
+
}
133
+
```
134
+
135
+
### Dependency Injection 💉
136
+
137
+
Middleware can also be used to provide dependencies to a `RequestContext` via a `provider`.
138
+
139
+
`provider` is a type of middleware that can return an object of type `T` and has access to a `RequestContext`. The `create` callback is called lazily and the injected `RequestContext` can be used to perform additional lookups to access values provided upstream.
140
+
141
+
In the following example, we'll use a `provider` to inject a `String` into our request context.
142
+
143
+
```dart
144
+
import 'package:dart_frog/dart_frog.dart';
145
+
146
+
Handler middleware(Handler handler) {
147
+
return handler
148
+
.use(requestLogger())
149
+
.use(provider<String>((context) => 'Welcome to Dart Frog!'));
150
+
}
151
+
```
152
+
153
+
We can later access the provided via from within a route handler using `context.read<T>()`:
154
+
155
+
```dart
156
+
import 'package:dart_frog/dart_frog.dart';
157
+
158
+
Response onRequest(RequestContext context) {
159
+
final greeting = context.read<String>();
160
+
return Response(body: greeting);
161
+
}
162
+
```
163
+
164
+
## Testing 🧪
165
+
166
+
In Dart Frog, we can unit test our route handlers and middleware effectively because they are just pure functions.
167
+
168
+
For example, we can test our route handler above using `package:test`:
169
+
170
+
```dart
171
+
import 'dart:io';
172
+
173
+
import 'package:dart_frog/dart_frog.dart';
174
+
import 'package:mocktail/mocktail.dart';
175
+
import 'package:test/test.dart';
176
+
177
+
import '../../routes/index.dart' as route;
178
+
179
+
class _MockRequestContext extends Mock implements RequestContext {}
180
+
181
+
void main() {
182
+
group('GET /', () {
183
+
test('responds with a 200 and greeting.', () async {
In the above test, we're using `package:mocktail` to create a mock `RequestContext` and stub the return value when calling `context.read<String>()`. Then, all we need to do is call `onRequest` with the mocked context and we can assert that the response is what we expect. In this case, we're checking the statusCode and response body to ensure that the response is a 200 with the provided greeting.
0 commit comments