/h4

A delightful way to build web servers with dart

Primary LanguageDartBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

og

A lightweight web framework for dart

Inspired by unjs H3, built with familiar API's and a functional style.

This is a new project under active development, production use is not advised.

The documentation site is a WIP - link

Features

  • Lightweight: H4 ships with a small core and a set of composable utilities.
  • Middleware: H4 comes with onRequest,onError and afterResponse middleware.
  • Generic Handlers: Specify the return type of your handler functions.

Getting Started

Add H4 to your pubspec.yaml:

dependencies:
  h4: ^1.0.0

Or install with dart pub get

dart pub add h4

Import the library and start building your server:

import 'package:h4/create.dart';

void main() {
 var app = createApp();
 var router = createRouter();

 app.use(router);

 router.get("/", (event) => "Hello world!");
}

Examples

Hello world

void main() {
  var app = createApp(port: 4000);
  var router = createRouter();

  app.use(router);

  router.get("/", (event) => "Hello world")
}

Generic handlers

Specify the return type of your handlers

router.get<bool>("/25/**", (event) => true);
router.get<int>("/42/**", (event) => 42);
router.get<String>("/hello/**", (event) => "Hello world");

Global Hooks

You can register global hooks:

  • onRequest
  • onError
  • afterResponse

These hooks are called for every request and can be used to add global logic to your app such as logging, error handling, etc.

 var app = createApp(
   port: 5173,
   onRequest: (event) => {},
   onError: (error, stacktrace, event) => {},
   afterResponse: (event) => {},
 );
 var router = createRouter();
 app.use(router);

Error Handling

You can throw a create error Exception that will terminate the request and send a 400 - Bad Request response

router.get('/error', (event) async {
 try {
  // Code that could fail.
 }
 catch(e) {
   throw CreateError(message: 'Womp Womp', errorCode: 400);
 }
});

The client recieves this json payload -

{
	"status": 400,
	"message": "Womp Womp"
}

Param Routing

You can define parameters in your routes using : prefix:

router.get('/users/:id', (event) {
 final userId = event.params['id'];
 return 'User $userId'
});

Wildcard Routing

// Matches 'articles/page' and '/articles/otherPage' but not 'articles/page/subPage'
router.get('/articles/*', (event) {
 final path = event.path;
 return 'The tea is teaing!!'
});
// Matches 'articles/foo/bar' and 'articles/page/subPage/subSubPage'
router.get('/articles/**', (event) {
 final path = event.path;
 return 'The tea is teaing!!'
});

Utilities

A set of composable utilities that help you add functionality to your server

readRequestBody

Reads the request body as json or text depending on the contentType of the request body.

router.post("/vamos", (event) async {
 var body = await readRequestBody(event);
 return body;
});

getHeader

Get the value of any of the incoming request headers. For convenience you can use the HTTPHeaders utility to get header strings.

router.post("/vamos", (event) async {
 var header = getHeader(event, HttpHeaders.userAgentHeader);
 return body;
});

Contributing

A great first PR would be improve the test coverage of this library, or adding a helpful util, for inspiration see here.

Running tests

In the root directory run

dart test

Code of Conduct.

Be cool and calm.