Getting Started

In this first guide, we will:

  • Download the angel_framework package from Pub.
  • Launch an AngelHttp server.
  • Add some basic routes to an app.
  • Add a 404 error handler.

The source code for this example can be found here:

https://github.com/angel-dart/examples-v2/tree/master/docs_examples/getting_started

First Steps

This tutorial relies on the terminal/command-line, so ifare not well-versed in using such tools, you shouldcopy/paste the snippets found on this page.

If you have not yet installed the Dart SDK, then it isrequired that you do so before continuing:

https://www.dartlang.org/tools/sdk#install

In addition, the curl tool will be used to send requeststo our server:

https://curl.haxx.se/download.html

Also, you will need to have the Dart SDK in yourPATH environment variable, so that the dart and pubexecutables can be found from your command line:

https://www.java.com/en/download/help/path.xml

Finally, note that some steps will mention Unix-specificprograms, like nano. Windows users should instead useNotepad. Alternative programs will be mentioned whererelevant.

Project Setup

The first thing we’ll need to do is create a newdirectory (folder) for our project.

  1. mkdir hello_angel
  2. cd hello_angel

Next, we create a pubspec.yaml file, and enter thefollowing contents:

  1. name: hello_angel
  2. dependencies:
  3. angel_framework: ^2.0.0

Now, just run pub get, which will install theangel_framework library, and its dependencies:

  1. Resolving dependencies... (3.3s)
  2. + angel_container 1.0.0
  3. + angel_framework 2.0.0
  4. + angel_http_exception 1.0.0+3
  5. (... more output omitted)
  6. Changed 33 dependencies!

Launching an HTTP Server

Angel can speak different protocols, but more often than not,we’ll want it to speak HTTP.

Create a directory named bin, and a file within bin namedmain.dart.

Your folder structure should now look like this:

  1. hello_angel
  2. bin/
  3. main.dart
  4. pubspec.yaml

Add the following to bin/main.dart:

  1. import 'package:angel_framework/angel_framework.dart';
  2. import 'package:angel_framework/http.dart';
  3. main() async {
  4. var app = Angel();
  5. var http = AngelHttp(app);
  6. await http.startServer('localhost', 3000);
  7. }

Next, in your terminal, run the commanddart bin/main.dart. Your server will now be running,and will listen for input until you kill it by enteringControl-C (the SIGINT signal) into the terminal.

Open a new terminal window, and type the following:

  1. curl localhost:3000 && echo

You’ll just see a blank line, but the fact that youdidn’t see an error means that the server is indeedlistening at port 3000.

Adding a Route

By adding routes to our server, we can respond to requestssent to different URL’s.

Let’s a handler at the root of our server, and printa simple Hello, world! message.

From this point, all new code needs to be added beforethe call to http.startServer (or else it will never run).

Add this code to your program:

  1. app.get('/', (req, res) => res.write('Hello, world!'));

bin/main.dart should now look like the following:

  1. import 'package:angel_framework/angel_framework.dart';
  2. import 'package:angel_framework/http.dart';
  3. main() async {
  4. var app = Angel();
  5. var http = AngelHttp(app);
  6. app.get('/', (req, res) => res.write('Hello, world!'));
  7. await http.startServer('localhost', 3000);
  8. }

(Note that this is the last time the entire file will bepasted, for the sake of brevity.)

Now, if you rerun curl localhost:3000 && echo, you’llsee the message Hello, world! printed to your terminal!

Route Handlers

Let’s break down the line we just added:

  1. app.get('/', (req, res) => res.write('Hello, world!'));

It consists of the following components:

  • A call to app.get
  • A string, '/',
  • A closure, taking two parameters: req and res
  • The call res.write('Hello, world!'), which isalso the return value of the aforementioned closure.

Angel.get is one of several methods (addRoute, post,patch, delete, head, get) that can be used toadd routes that correspond toHTTP methodsto an Angel server instance.

Combined with the path, '/', this signifies that whenevera request is sent to the root of our server, which inthis case is the URL http://localhost:3000, the attachedclosure should be invoked.

The path is important because it defines the conditions underwhich code should run. For example, if we were to visithttp://localhost:3000/foo, we’d just see a blank line printedagain, because there is no route mounted corresponding tothe path '/foo'.

The two parameters, req and res, hold the typesRequestContext and ResponseContext, respectively.We’ll briefly cover these in the next section.

Finally, we call res.write, which, as you may have surmised,prints a value to the outgoing HTTP response. That’s howwe are able to print Hello, world!.

Printing Headers

Just as their names suggest, the RequestContextand ResponseContext classes are abstractions used toread and write data on the Web.

By reading the property req.headers, we can access theHTTP headerssent to us by the client:

  1. app.get('/headers', (req, res) {
  2. req.headers.forEach((key, values) {
  3. res.write('$key=$values');
  4. res.writeln();
  5. });
  6. });

Run the following:

  1. curl -H 'X-Foo: bar' -H 'Accept-Language: en-US' \
  2. http://localhost:3000/headers && echo

And you’ll see output like the following:

  1. user-agent=[curl/7.54.0]
  2. accept=[*/*]
  3. accept-language=[en-US]
  4. x-foo=[bar]
  5. host=[localhost:3000]

Reading Request Bodies

Web applications very often have users send data upstream,where it is then handled by the server.

Angel has built-in functionality for parsing bodies of threeMIME types:

  • application/json
  • application/x-www-form-urlencoded
  • multipart/form-data

(You can also handle others, but that’s beyond the scopeof this demo.)

So, as long as the user sends data in one of the above forms,we can handle it in the same way.

Add the following route.It will listen on the path '/greet' for aPOST request, and then attempt to parse theincoming request body.

Afterwards, it reads the name value from the body,and computes a greeting string.

  1. app.post('/greet', (req, res) async {
  2. await req.parseBody();
  3. var name = req.bodyAsMap['name'] as String;
  4. if (name == null) {
  5. throw AngelHttpException.badRequest(message: 'Missing name.');
  6. } else {
  7. res.write('Hello, $name!');
  8. }
  9. });

To visit this, enter the following curl command:

  1. curl -X POST -d 'name=Bob' localhost:3000/greet && echo

You should see Hello, Bob! appear in your terminal.

Adding an Error Handler

In the previous example, you might have noticed thisline:

  1. throw AngelHttpException.badRequest(message: 'Missing name.');

Angel handles errors thrown while calling route handlers,preventing your server from crashing. Ultimately,all errors are wrapped in the AngelHttpException class, orsent as-is if they are already instances of AngelHttpException.

By default, either an HTML page is printed, or a JSON messageis displayed (depending on the client’s Accept header).In many cases, however, you might want to do something else,i.e. rendering an error page, or logging errors through a servicelike Sentry.

To add your own logic, set the errorHandler of yourAngel instance. It is a function that accepts 3 parameters:

  • AngelHttpException
  • RequestContext
  • ResponseContext
  1. var oldErrorHandler = app.errorHandler;
  2. app.errorHandler = (e, req, res) {
  3. if (e.statusCode == 400) {
  4. res.write('Oops! You forgot to include your name.');
  5. } else {
  6. return oldErrorHandler(e, req, res);
  7. }

Note that we kept a reference to the previous error handler,so that existing logic can be reused if the case we wrotefor is not handled.

To trigger a 400 Bad Request and see our error handler inaction, run the following:

  1. curl -H 'Content-Type: application/x-www-form-urlencoded' \
  2. -X POST localhost:3000/greet && echo

You will now see 'Oops! You forgot to include your name.'printed to the console.

Conclusion

Congratulations on creating your first Angel server!Hopefully this is just one of many more to come.

The choice is now yours: either continue reading theother guides posted on this site, or tinker around andlearn the ropes yourself.

You can find angel_* packages on the Pub site, andread the documentation found in theirrespective README files:

https://pub.dartlang.org/packages?q=dependency%3Aangel_framework

Don’t forget that for discussion and support, you can eitherfile a Github issue, or join the Gitter chat:

https://gitter.im/angel_dart/discussion