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
+6-218Lines changed: 6 additions & 218 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,6 +16,10 @@ Developed with π by [Very Good Ventures][very_good_ventures_link] π¦
16
16
17
17
Dart Frog is an experimental project under development and should not be used in production at this time.
18
18
19
+
## Documentation π
20
+
21
+
For official documentation, please visit https://verygoodopensource.github.io/dart_frog.
22
+
19
23
## Quick Start π
20
24
21
25
### Prerequisites π
@@ -88,240 +92,24 @@ Dart Frog provides a simple core with a small API surface area in order to reduc
88
92
89
93
β Docker π³
90
94
95
+
β Static File Support π
96
+
91
97
π§ Generated Dart Client Package π¦
92
98
93
99
π§ Generated API Documentation π
94
100
95
-
## Documentation π
96
-
97
-
### Routes π
98
-
99
-
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.
100
-
101
-
For example, if you create `routes/hello.dart` that exports an `onRequest` method like below, it will be accessible at `/hello`.
102
-
103
-
```dart
104
-
import 'package:dart_frog/dart_frog.dart';
105
-
106
-
Response onRequest(RequestContext context) {
107
-
return Response(body: 'Hello World');
108
-
}
109
-
```
110
-
111
-
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).
112
-
113
-
```dart
114
-
import 'package:dart_frog/dart_frog.dart';
115
-
116
-
Response onRequest(RequestContext context) {
117
-
// Access the incoming request.
118
-
final request = context.request;
119
-
120
-
// Return a response.
121
-
return Response(body: 'Hello World');
122
-
}
123
-
```
124
-
125
-
We can customize the status code of the response via the `statusCode` parameter on the `Response` object:
126
-
127
-
```dart
128
-
import 'package:dart_frog/dart_frog.dart';
129
-
130
-
Response onRequest(RequestContext context) {
131
-
return Response(statusCode: 204);
132
-
}
133
-
```
134
-
135
-
In addition, we can return JSON via the `Response.json` constructor:
136
-
137
-
```dart
138
-
import 'package:dart_frog/dart_frog.dart';
139
-
140
-
Response onRequest(RequestContext context) {
141
-
return Response.json(
142
-
body: <String, dynamic>{'hello': 'world!'},
143
-
);
144
-
}
145
-
```
146
-
147
-
We can also return any Dart object in the `body` of the `Response.json` constructor and it will be serialized correctly as long as it has a `toJson` method that returns a `Map<String, dynamic>`.
148
-
149
-
π‘ _Tip: Check out [json_serializable](https://pub.dev/packages/json_serializable) to automate the `toJson` generation_.
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.
191
-
192
-
Routing parameters are forwarded to the `onRequest` method as seen below.
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, provide dependencies, and more!
205
-
206
-
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.
207
-
208
-
```dart
209
-
import 'package:dart_frog/dart_frog.dart';
210
-
211
-
Handler middleware(Handler handler) {
212
-
return (context) async {
213
-
// Execute code before request is handled.
214
-
215
-
// Forward the request to the respective handler.
216
-
final response = await handler(context);
217
-
218
-
// Execute code after request is handled.
219
-
220
-
// Return a response.
221
-
return response;
222
-
};
223
-
}
224
-
```
225
-
226
-
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.
227
-
228
-
```dart
229
-
import 'package:dart_frog/dart_frog.dart';
230
-
231
-
Handler middleware(Handler handler) {
232
-
return handler.use(requestLogger());
233
-
}
234
-
```
235
-
236
-
#### Dependency Injection π
237
-
238
-
Middleware can also be used to provide dependencies to a `RequestContext` via a `provider`.
239
-
240
-
`provider` is a type of middleware that can create and provide an instance of type `T` to the request context. The `create` callback is called lazily and the injected `RequestContext` can be used to perform additional lookups to access values provided upstream.
241
-
242
-
In the following example, we'll use a `provider` to inject a `String` into our request context.
243
-
244
-
```dart
245
-
import 'package:dart_frog/dart_frog.dart';
246
-
247
-
Handler middleware(Handler handler) {
248
-
return handler
249
-
.use(requestLogger())
250
-
.use(provider<String>((context) => 'Welcome to Dart Frog!'));
251
-
}
252
-
```
253
-
254
-
We can later access the provided via from within a route handler using `context.read<T>()`:
255
-
256
-
```dart
257
-
import 'package:dart_frog/dart_frog.dart';
258
-
259
-
Response onRequest(RequestContext context) {
260
-
final greeting = context.read<String>();
261
-
return Response(body: greeting);
262
-
}
263
-
```
264
-
265
-
### Testing π§ͺ
266
-
267
-
In Dart Frog, we can unit test our route handlers and middleware effectively because they are plain functions.
268
-
269
-
For example, we can test our route handler above using `package:test`:
270
-
271
-
```dart
272
-
import 'dart:io';
273
-
274
-
import 'package:dart_frog/dart_frog.dart';
275
-
import 'package:mocktail/mocktail.dart';
276
-
import 'package:test/test.dart';
277
-
278
-
import '../../routes/index.dart' as route;
279
-
280
-
class _MockRequestContext extends Mock implements RequestContext {}
281
-
282
-
void main() {
283
-
group('GET /', () {
284
-
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.
297
-
298
-
### Additional Resources π
299
-
300
-
-[Example][example_link]
301
-
-[Roadmap][roadmap_link]
302
-
-[Blog post][blog_link]
303
-
-[Livestream demo][livestream_link]
304
-
305
-
_π‘ Fun Fact: the [dart2js][dart2js_compiler_link] compiler [used to be called frog][dart2js_frog_pr_link]._
Dart Frog supports serving static files including images, text, json, html, and more. To serve static files, place the files within the `public` directory at the root of the project.
8
+
9
+
For example, if you create a file in `public/hello.txt` which contains the following:
10
+
11
+
```
12
+
Hello World!
13
+
```
14
+
15
+
The contents of the file will be available at [http://localhost:8080/hello.txt](http://localhost:8080/hello.txt).
16
+
17
+
The `public` directory can contain static files within subdirectories. For example, if you created an image in `public/images/unicorn.png`, the contents of the file will be available at [http://localhost:8080/images/unicorn.png](http://localhost:8080/images/unicorn.png)
18
+
19
+
When running a development server, static files can be added, removed, and modified without needing to restart the server thanks to hot reload β‘οΈ.
20
+
21
+
:::note
22
+
Static file support requires `dart_frog ^0.0.2-dev.7` and `dart_frog_cli ^0.0.1-dev.8`
23
+
:::
24
+
25
+
:::note
26
+
The `/public` folder must be at the root of the project and cannot be renamed. This is the only directory used to serve static files.
27
+
:::
28
+
29
+
:::note
30
+
In production, only files that are in the `/public` directory at build time will be served.
31
+
:::
32
+
33
+
:::caution
34
+
Be sure not to have a static file with the same name as a file in the `/routes` directory as this will result in a conflict.
0 commit comments