---
title: Dart Frog — A minimalistic backend framework for Dart
description: Dart Frog is an experimental framework created by TMZ Software. This is a fantastic tool, helping developers to have a unified tech stack and share models, logic, and other parts of the application. Because this…
author: Razvan Tamazlicariu
pubDate: 2019-05-09
tags:
  - Dart
  - Dart Frog
featured: false
heroImage: /images/blog/cdn/ec30bb05d893adeb.webp
heroAlt: "Dart Frog — A minimalistic backend framework for Dart"
---

![Dart Frog minimalistic backend framework for Dart](/images/blog/cdn/6340bbf75d4169ec.webp)

Dart Frog is an experimental framework created by [**TMZ Software**](https://www.tmz-software.com/). This is a fantastic tool, helping developers to have a unified tech stack and share models, logic, and other parts of the application.

Because this project is still under development, I don’t recommend it to be used in production.

### **Supported features:**

1.  Hot Reload ⚡️

2.  Dart Dev Tools ⚙️

3.  File System Routing 🚏

4.  Index Routes 🗂

5.  Nested Routes 🪆

6.  Dynamic Routes 🌓

7.  Middleware 🍔

8.  Dependency Injection 💉

9.  Production Builds 👷‍♂️

10. Docker 🐳

11. Static File Support

As for now, these are the only features available. Support for web sockets or things like protobuff support, web rtc, and authentication are not available at the moment. You can check the roadmap [**here**](https://dartfrog.vgv.dev/docs/roadmap).

### **Source code:**

You can skip. ahead and download the source code [HERE](https://github.com/razvantmzz/medium_articles/tree/dart_frog_demo)

#### **Getting Started**

The easiest way to start is by installing the [**dart_frog_cli**](https://pub.dev/packages/dart_frog_cli)**.** To install the CLI, open the terminal and type the following command:

```
# Install from pub.dev
dart pub global activate dart_frog_cli
```

At this point, **dart_frog** should be available. You can verify by running **dart_frog** in your terminal.

### **Create a project**

Simply run this command. This will create a folder with everything you need inside.

```
dart_frog create name_of_your_project
```

### **Start dev server:**

By default, dev server will start on port 8080.

```
# Start dev server
dart_frog dev
# Server is now running at: http://localhost:8080/
```

### **Create a Production Build**

Create a production build that includes a `DockerFile` so that you can deploy anywhere:

```
# Create a production build
dart_frog build
```

### **Creating a new Route**

In dart_frog a route is represented by an **onRequest** function, also called a route handler, exported from a dart file in the routes directory. Each file represents an endpoint, named after the file. Files named **index.dart** will correspond to a **/** endpoint

For example, if you create a file in **routes/username/index.dart** that exports an **onRequest** method, you can access the endpoint via **/username**.

To create this route create a folder `username` in `routes`.Inside `routes/username` create an `index.html` file and paste this:

```
import 'package:dart_frog/dart_frog.dart';
Response onRequest(RequestContext context) {
  return Response(body: '[{"username": "Alex"}]');
}
```

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.

**OnRequest** will get called for each HTTP request method. In order to differentiate between GET or POST you have to manually check the type:

```
switch (method) {
  case HttpMethod.get:
    // TODO: GET method
  break;
  case HttpMethod.post:
  // TODO: POST method
  break;
  case HttpMethod.put:
  // TODO: PUT method
  break;
  case HttpMethod.delete:
  // TODO: DELETE method
  break;
}
```

### **Synchronous vs Asynchronous**

By default, route handlers are synchronous. To create an asynchronous route handler, we need to add the keyword `async` and return a `Future<Response>.`

```
Future<Response> onRequest(RequestContext context) async {
  return Response(body: '[{"username": "Alex"}]');
}
```

### **Returning a response**

**OnRequest** function returns a **Response.** We can customize the status code of the response via the **statusCode** parameter. We can also return a JSON response via the **Response.json** constructor.

```
Response onRequest(RequestContext context) {
  return Response.json(
    statusCode: 404,
    body: <String, dynamic>{'hello': 'world!'},
  );
}
```

### **Dynamic routing**

Dynamic routing in dart_frog is a little strange. If we want an endpoint, that returns the username given an id, we would access an URL that looks like this: `**/username/1**` **,** where 1 is the id. In dart_frog we know that each route is represented by a file. In the `**username**` folder create a file named `**[id].dart**` .

Routing parameters are forwarded to the **onRequest** method as below:

```dart
Response onRequest(RequestContext context, String id) {
  return Response.json(body: <String, dynamic>{'id': id});
}
```

### **Middleware**

Middleware allows you to execute code before and after a request is processed. You can modify the inbound and outbound responses, provide dependency injections, log the request, etc. This is useful for validating authorization tokens, adding common headers, logging, etc.

Just like routes, middleware consists of 2 parts: a file, with a specific place and name, and a **middleware function.** The file needs to be placed within a subdirectory of the routes folder and there can be only **1 middleware file** in the same subdirectory.

The middleware is executed for all routes in the same subdirectory. For example, placing a middleware file in **/routes** will get executed for all endpoints. Placing it in the **/routes/username** directory will get executed for the routes under the **/username directory.**

To create a middleware, add a file named **\_middleware.dart** and paste the middleware handler:

```
import 'package:dart_frog/dart_frog.dart';

Handler middleware(Handler handler) {
  return (context) async {
    // Execute code before request is handled.

    // Forward the request to the respective handler.
    final response = await handler(context);

    // Execute code after request is handled.

    // Return a response.
    return response;
  };
}
```

For logging request we have a build in middleware called `requestLogger()` .

We can chain middleware via the **use** extension. Chained middleware are executed in the order they are added before the request is executed, and in the inverted order after the request is executed.

```
A -> B -> C -> execute request -> C -> B -> A
```

```
import 'package:dart_frog/dart_frog.dart';
Handler middleware(Handler handler) {
   return handler
          .use(requestLogger())
          .use(mainHandler());
}
Middleware mainHandler() {
   return (handler) {
      return (context) async {
        // Execute code before request is handled.
        // Forward the request to the respective
     handler.print("methods type before ${context.request.method}");
        final response = await handler(context);
        print("methods type after ${context.request.method}");
        // Execute code after request is handled.
        // Return a response.
       return response;
    };
  };
}
```

Be careful to chain the `**.use()**.`

```
// DON'T
return handler
       ..use(requestLogger())
       ..use(mainHandler());
// OR
handler.use(requestLogger())
handler.use(mainHandler());
return handler;
//CORRECT WAY
return handler.use(requestLogger()).use(mainHandler());
```

### **Dependency injection**

Middleware can also be used to provide dependencies to a **RequestContext** with the help of a provider.

**Provider** is a different type of middleware. It can create and provide an instance of a class or type T to the `RequestContext` . The create callback is called lazily.

I created a class called **Username** in `lib/usernames.dart`which returns a random name.

```
///Holder class for returning a random username
class Usernames {
  final List<String> _usernames = [
    'Andrei91',
    'Rabit123',
    'Codingcamp44',
  ];
late final _random = Random();
///Returns a random name
  String getName() {
    final index = _random.nextInt(_usernames.length);
    return _usernames.elementAt(index);
  }
}
```

Next, in `**_/routes/username_**` we create a new middleware. We want to inject the `Username` class, just for routes under **_username_**.

We’ll use **provider** to inject the **Username()** instance into our request context.

```
import 'package:dart_frog/dart_frog.dart';
import 'package:frog_playground/usernames.dart';
Handler middleware(Handler handler) {
  return handler.use(provider<Usernames>((context) => Usernames()));
}
```

Later, **Usernames** can be accessed from within a route handler using `**_context.read<T>():_**`

```
import 'package:dart_frog/dart_frog.dart';
import 'package:frog_playground/usernames.dart';
Response onRequest(RequestContext context) {
  final username = context.read<Usernames>();
return Response.json(
    body: <String, dynamic>{'username': username.getName()},
  );
}
```

### **Debug dart_frog in VS Code:**

If you want to debug in VS Code instead of Debug Dart Tools, follow these steps:

1.  run dart_frog dev inside VsCode terminal

2.  copy DevTools Debugger Url. should look like this:

http://127.0.0.1:8181/nYPpoWRg8g8=/devtools**/#**/?uri=ws%3A%2F%2F127.0.0.1%3A8181%2FnYPpoWRg8g8%3D%2Fws

3\. Delete “/#” after **devtools** from the URL. It should look like this:

http://127.0.0.1:8181/nYPpoWRg8g8=/devtools/?uri=ws%3A%2F%2F127.0.0.1%3A8181%2FnYPpoWRg8g8%3D%2Fws

4\. Press **Command + P,** on Mac( opens navigate to any file window) and write: `> Debug: Attach to Dart Process` hit enter and paste the Url from step 3.

That's it.
