Tutorials
Dificulty: Beginner
Length: 5 minutes
Before you start, make sure you have the Dart SDK installed on your machine.
Overview
Sarus is a lightweight backend framework for Dart, built on top of Shelf with a modular approach. It provides a simple and efficient way to create web applications and APIs.
When we say modular
, we mean that Sarus allows you to build your application in a modular way, where each module can be developed, tested, and maintained independently. This makes it easier to manage large applications and promotes code reuse.
Creating a Project
To create a new Sarus project, you can use the sarus create
command. This command will generate a new project structure with the necessary files and directories.
sarus create hello_world
This will create a new directory called hello_world
with the following structure:
├── bin
│ └── server.dart
├── lib
│ ├── config
│ │ └── router.dart
│ ├── greeting
│ │ ├── endpoints.dart
│ │ └── middlewares.dart
│ └── sarus_application.dart
│ └── sarus_application.g.dart
├── test
│ └── hello_world_test.dart
├── analysis_options.yaml
├── config.yaml
├── .gitignore
├── pubspec.yaml
└── README.md
Running the Project
To run the project, navigate to the project directory and use the sarus dev
command:
cd hello_world
sarus dev
This will start the development server, and you can access your application at http://localhost:8080/greeting.
Loading configuration...
Starting Sarus server...
Server listening on port 8080
Make sure it's running by opening your browser and navigating to http://localhost:8080/greeting. You should see a response like this:
{
"message": "Hello from GreetingEndpoint"
}
Creating a Module
To create a new module, you can use the sarus module hello
command. This command will generate a new module structure with the necessary files and directories.
sarus module hello
This will create a new directory called hello
with the following structure:
├── endpoints.dart
└── middlewares.dart
You can then add your endpoints and middlewares to the endpoints.dart
and middlewares.dart
files, respectively.
Adding an Endpoint
To add an endpoint to your module, you can define a function that returns a Response
object. For example, in the endpoints.dart
file of the hello
module, you can add the following code:
import 'dart:convert';
import 'package:hello_world/hello/middlewares.dart';
import 'package:sarus/sarus.dart';
@Endpoint(path: '/hello')
class HelloEndpoints extends Endpoints {
HelloEndpoints() : super();
@Get()
Future<Response> index(
Request request,
@QueryParam('name') String name,
) async {
return Response.ok(
jsonEncode({
'message': 'Hello, World! from $name',
}),
);
}
@override
RouterConfig get router => _$helloEndpointsRouterConfig(this);
@override
Handler get handler =>
const Pipeline().addMiddleware(helloMiddleware).addHandler(router.call);
}
This code defines an endpoint at /hello
that responds with a JSON object containing a greeting message. The @QueryParam
annotation allows you to pass a query parameter called name
to the endpoint.
Similarly, you can add more endpoints to the HelloEndpoints
class by defining more methods with the appropriate HTTP method annotations (@Get()
, @Post()
, etc.). You can also use the @PathParam
annotation to extract path parameters from the request URL.
Adding a Middleware
To add a middleware to your module, you can define a function that takes a Handler
and returns a Handler
. For example, in the middlewares.dart
file of the hello
module, you can add the following code:
import 'package:sarus/sarus.dart';
Middleware helloMiddleware = createMiddleware(
requestHandler: (request) {
print('Hello Request: ${request.method} ${request.requestedUri}');
return null;
},
);
This code defines a middleware that logs the request method and URL to the console. You can add this middleware to your endpoint by using the addMiddleware
method on the Pipeline
class.
Add the endpoint to the Router
To add the HelloEndpoints
to the router, you can modify the router.dart
file in the config
directory. You can import the HelloEndpoints
class and add it to the router configuration.
import 'package:hello_world/greeting/endpoints.dart';
import 'package:hello_world/hello/endpoints.dart';
import 'package:sarus/sarus.dart';
final router = Router(
globalMiddleware: [logRequests()],
routes: [
Route(
endpoints: [GreetingEndpoints()],
),
Route(
endpoints: [HelloEndpoints()],
),
],
);
Note: Each Route
can have multiple endpoints, and you can add as many routes as you need. The globalMiddleware
is applied to all routes.
Running the Project Again
After making these changes, you can run the project again using the sarus dev
command:
sarus dev
You can now access the new endpoint at http://localhost:8080/hello?name=YourName. You should see a response like this:
{
"message": "Hello, World! from YourName"
}
Pass Request Body to Endpoint
To pass a request body to an endpoint, you can use the @Body
annotation. For example, you can modify the HelloEndpoints
class to include a new endpoint that accepts a JSON body:
First, we need to create a model class to represent the request body. Create a new file called models.dart
in the hello
module:
import 'package:sarus/sarus.dart';
@DTO()
class UserModel {
UserModel({
required this.firstName,
required this.lastName,
this.email,
this.age,
});
factory UserModel.fromJson(Map<String, dynamic> json) =>
_$userModelFromJson(json);
@JsonKey(name: 'first_name', includeIfNull: false)
final String firstName;
@JsonKey(name: 'last_name', includeIfNull: false)
final String lastName;
final String? email;
final int? age;
Map<String, dynamic> toJson() => _$userModelToJson(this);
}
Note: The @DTO()
annotation is used to generate the serialization and deserialization code for the model class. The part
directive is used to include the generated code. Each DTO class must have fromJson
method to deserialize the JSON data and a toJson
method to serialize the object back to JSON.
Now, Run the following command to generate the serialization code:
dart run build_runner build --delete-conflicting-outputs
Next, modify the HelloEndpoints
class to include a new endpoint that accepts a JSON body:
import 'dart:convert';
import 'package:hello_world/hello/middlewares.dart';
import 'package:hello_world/hello/models.dart';
import 'package:sarus/sarus.dart';
@Endpoint(path: '/hello')
class HelloEndpoints extends Endpoints {
HelloEndpoints() : super();
@Post(path: '/<id>')
Future<Response> index(
Request request,
@QueryParam('name') String name,
@PathParam('id') String id,
@Body() UserModel user,
) async {
return Response.ok(
jsonEncode({
'message': 'Hello, World! from $name',
'id': id,
'user': user.toJson(),
}),
);
}
@override
RouterConfig get router => _$helloEndpointsRouterConfig(this);
@override
Handler get handler =>
const Pipeline().addMiddleware(helloMiddleware).addHandler(router.call);
}
This code defines a new endpoint at /hello/<id>
that accepts a POST request with a JSON body. The @Body()
annotation is used to extract the request body and deserialize it into a UserModel
object.
Again, you need to run the build runner to generate the necessary code for the HelloEndpoints
class:
dart run build_runner build --delete-conflicting-outputs
or you can use the watch
command to automatically regenerate the code whenever you make changes:
dart run build_runner watch --delete-conflicting-outputs
Now, you can test the new endpoint by sending a POST request with a JSON body. You can use a tool like Postman or cURL to send the request. Here's an example using cURL:
curl -X POST http://localhost:8080/hello/123?name=YourName \
-H "Content-Type: application/json" \
-d '{"first_name": "John", "last_name": "Doe", "email": "email@example.com", "age": 30}'
You should see a response like this:
{
"message": "Hello, World! from YourName",
"id": "123",
"user": {
"first_name": "John",
"last_name": "Doe",
"email": "email@example.com",
"age": 30
}
}
This response includes the id
from the URL path and the user
object from the request body. You can modify the UserModel
class to include any additional fields you need, and Sarus will handle the serialization and deserialization for you.
Congratulations!
You have successfully created a Sarus project, added a module, created an endpoint, and added a middleware. You can now continue to build your application by adding more modules, endpoints, and middlewares as needed.
Conclusion
In this tutorial, you learned how to create a Sarus project, run it, create a module, add an endpoint, and add a middleware. Sarus provides a simple and efficient way to build web applications and APIs in Dart, allowing you to focus on your application's logic without worrying about the underlying infrastructure.