So, what’s Aqueduct?

Well it’s an open-source framework for creating and deploying RESTful web apis on the server. It has a similar flavour to Express and Hapi, even .NET Web API, offering a point of entry with a comprehensive list of features.

My favourite ones are:

Fluid, chainable routing. A functional style to composing your routes and its handler methods A CLI tool. This allows you to scaffold your next project by issuing commands Multi-threading out of the box. Spins up multiple instances of your application via Dart’s “isolates”, scaling across all CPU cores on the server. Has an inbuilt ORM. A must-have if you work with relational databases! Also supports database migration. Has an integrated testing library. Because you need to test all the things! Plays well with tools like TravisCI.

In the series we will be building an api for a personal reading list (let’s call it FaveReads 📚), covering these topics:

via Giphy

Setting up and running the example

If you haven’t already, I’d encourage you to install the Dart SDK. There are instructions for Windows, Mac and Linux.

You can confirm you have Dart running by checking the terminal:

dart --version

Dart comes with a tool called pub to manage its packages. Let’s use this tool to install Aqueduct:

pub global activate aqueduct

This gives us access to the aqueduct executable. Change to your working directory and let us create our project:

aqueduct create fave_reads && cd fave_reads

You should now be in the fave_reads directory with all the project files. For now we’ll focus on:

bin/

main.dart

lib/

fave_reads_sink.dart

pubspec.yaml

bin/main.dart creates our server and starts the app

creates our server and starts the app lib/fave_reads_sink.dart sets up your application with its configuration

sets up your application with its configuration pubspec.yaml contains metadata about the project. Similar to having a package.json for Node.js development

Let’s start the application using either commands below:

aqueduct serve # or `dart bin/main.dart`

And here we go:

We now have a server running at http://localhost:8081 with /example being the only created route. Accessing http://localhost:8081/example will return the response below:

{ "key": "value" }

At this point its worth mentioning that Aqueduct has the concept of a RequestSink, which according to the documentation:

handles the initialization of an application, including setting up routes, authorization and database connections.

An application needs one RequestSink subclass to enable it to receive requests. Our example has a FaveReadsSink extending the base RequestSink class to enable us to override its methods with our own implementation. The methods in particular are setupRouter and willOpen . The first method will allow us to define our routes with associated controllers and other middleware, while the latter allows us to perform any asynchronous initialisation after the routes are set up and before the application can receive requests.

The default response type is set to JSON for current requests. However this can be set to whatever content type is appropriate to meet our needs.

Let’s demonstrate this by creating a second route in setupRouter method:

router.route('/').listen((request) async {

return new Response.ok('Hello world')

..contentType = ContentType.TEXT;

});

Using method cascades, we are able to set the contentType property to text/plain . The ContentType utility comes inbuilt with Dart and can be used through the style below:

new ContentType(primaryType, subType, {String charset, Map parameters});

It’s already got constants for HTML, JSON and TEXT so in most scenarios you should just use those.

Now restart the server by killing the current process and running aqueduct serve again. Accessing the root path should now give you this:

Bingo!

Before we wrap up, lets scale up our application instances to the number of cores we have. In bin/main.dart it is currently set to 2 when app.start is invoked:

await app.start(numberOfInstances: 2);

To resolve this, we will import Dart’s Platform class from the “dart:io” library and amend main.dart as follows:

import 'dart:io' show Platform; Future main() async {

...

...

await app.start(numberOfInstances: Platform.numberOfProcessors);

...

}

Some development tips for VS Code 👈

Firstly, make sure to install the Dart extension by Dart Code, to enable Dart and Flutter support.

Secondly, add a launch configuration for Dart with this setting:

{

"name": "Dart",

"type": "dart",

"request": "launch",

"program": "${workspaceFolder}/bin/main.dart"

}

This will allow you to run the app through VS Code with the ability to add breakpoints to help with debugging: