les 0.0.5

Light Efficient Server - for creating servers on Dart. Inspired by ExpressJS and Koa #

Created under a MIT-style license.

Overview #

The server builds by creating instance of Server class. It have few methods for adding Middlewares and Routes to handling incoming requests.

You can create server that is listening for requests over default http scheme, over https (secure) scheme or via socket.

Server() // or Server.secure(...) of Server.socket(...)
    ..use(...) // Add middlewares
    ..add(...) // Add routes
    ..listen(2000); // Start listen to requests

Route #

One of the main concept of library is Route class that  describes the response for a particular path. It accepts path, function that describe how to create response for such request, optionally method of the request and middlewares.

Route(
    '/',
    (Context ctx) => ctx.send('Hello world'),
    method: HttpMethod.get // default. No need to be provided
);

If exist many routes that starts with the same path prefix, then you can provide a Router. Its just a collection of Routes for paths that start with identical prefix. Or you can use Router if you need handle requests with the same paths, but different http methods.

// Define [Route]s that describe answers for concrete requests
final routeOne = Route(
        r'/:a(\d+)', // Will match /identical/5, /83645, but not /identical/word or other symbols
        (ctx) => ctx.send('Hello get')
      );
final routeTwo = Route(
      '/b',
      (ctx) => ctx.send('Hello post'),
      method: HttpMethod.post
      )
final routeThree = Route(
      '', // If you left empty path, then it will be sets to `Router`'s /identical
      (ctx) => ctx.send('Hello put'),
      method: HttpMethod.put
      )
final routes = Router('/identical');
  ..addAll(<Route>[routeOne, routeTwo, routeThree]);

All paths that are defined in Route or Router transforms to RegExp and parses by path_to_regexp package. For more info about constructing and managing paths see its documentation. Thanks to this you can provide parameter variable in path and sets to it some bounds.

Middleware #

Middleware is like a Route controller, except that it isn't send responses to client, but just process request before routes does. It is useful for processing some work before sending a response. Middleware must not sends a response to the client!

Middleware(
    (Context ctx) => // do come work over ctx object
);

Middlewares can be provided before each route in Server, before group of routes in Router or before specific Route.

Context #

The other main concept of this library is Context class. It contains the request object and build a response object. Handlers of Route and Middleware receive this object. It has various convenient methods for sending a responses and properties for reading request details or construct response (headers, ...). For details about methods and properties see dartdoc.

Predefined middlewares #

  1. bodyParser: with library ships bodyParser middleware that process context object and parses its body if it exists. The content body is parsed, depending on the Content-Type header field. When the full body is read and parsed the body content is made available.

The following content types are recognized:

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

For content type text/* the body is decoded into a String. The 'charset' parameter of the content type specifies the encoding used for decoding. If no 'charset' is present the default encoding of ISO-8859-1 is used.

For content type application/json the body is decoded into a string which is then parsed as JSON. The resulting body is a Map. The 'charset' parameter of the content type specifies the encoding used for decoding. If no 'charset' is present the default encoding of UTF-8 is used.

For content type application/x-www-form-urlencoded the body is a query string which is then split according to the rules for splitting a query string. The resulting body is a Map<String, String>. If the same name is present several times in the query string, then the last value seen for this name will be in the resulting map. The encoding US-ASCII is always used for decoding the body.

For content type multipart/form-data the body is parsed into it's different fields. The resulting body is a Map<String, dynamic>, where the value is a String for normal fields and a HttpBodyFileUpload instance for file upload fields. If the same name is present several times, then the last value seen for this name will be in the resulting map.

When using content type multipart/form-data the encoding of fields with String values is determined by the browser sending the HTTP request with the form data. The encoding is specified either by the attribute accept-charset on the HTML form, or by the content type of the web page containing the form. If the HTML form has an accept-charset attribute the browser will use the encoding specified there. If the HTML form has no accept-charset attribute the browser determines the encoding from the content type of the web page containing the form. Using a content type of text/html; charset=utf-8 for the page and setting accept-charset on the HTML form to utf-8 is recommended as the default for HttpBodyHandler is UTF-8. It is important to get these encoding values right, as the actual multipart/form-data HTTP request sent by the browser does not contain any information on the encoding.

For all other content types the body will be treated as uninterpreted binary data. The resulting body will be of type List<int>.

Server()
    ..use(bodyParser) // Add bodyParser
    ..use(...) // Add middlewares
    ..add(...) // Add routes
    ..listen(2000); // Start listen to requests
  1. staticFilesHandler: builds static files handler for provided path to static(default) folder. Path starts from the root of project and in that level must be folder that contains all static files. All files will be stored in Context object for current session. Note that context doesn't store actual files, instead it will contain File objects with some info about actual file. You must read and convert that files by yourself. If directory isn't exist context object will have empty Map<String, File> object.
Server()
    ..use(bodyParser) // Add bodyParser
    ..use(buildStaticFilesHandler()) // Add staticFilesHandler
    ..use(...) // Add middlewares
    ..add(...) // Add routes
    ..listen(2000); // Start listen to requests
  1. cors: sets appropriate headers to response and enable CORS.
Server()
    ..use(bodyParser) // Add bodyParser
    ..use(buildStaticFilesHandler()) // Add staticFilesHandler
    ..use(cors()) // Add cors
    ..use(...) // Add other middlewares
    ..add(...) // Add routes
    ..listen(2000); // Start listen to requests

Usage #

See example.

Features and bugs #

Please file feature requests and bugs at the issue tracker.

0.0.5 #

  • Add Server.secure constructor for establishing HTTPS connection and Server.socket constructor for establishing connection via socket.
  • Downgrade sdk to 2.1.0-dev.9.4 and some packages.
  • Add cors middleware.
  • Edit README.

0.0.4 #

  • Add session getter to Context object.
  • Change checking route match to specific request (non-breaking fix).
  • Make all methods of Context object asynchronous.
  • Edit README.

0.0.3+1 #

  • Edit README.
  • Rename files field of Context to staticFiles.

0.0.3 #

  • Add staticFilesHandler middleware.
  • Add files field to Context object.
  • Edit README.

0.0.2 #

  • Change bodyParser to parse body in put, post, patch and delete http methods.
  • Add default error response 501 if route for request isn't provided.

0.0.1 #

  • Initial version.
  • Creates core of the package. See README.

example/example.dart

import 'package:les/les.dart';

void main(List<String> args) {
  // Creates instance of [Server]
  Server()
  // Add middlewares
  ..use(bodyParser)
  ..use(buildStaticFilesHandler())
  // Add [Routes]
    ..add(routes)
    // Start listen for requests
    ..listen(7575);
}

// Define [Route]s that describe answers for concrete requests
final routes = Router('/')
  ..add(Route(
        // Path will be transformed to RegExp => (:number)
        r':a(\d+)',
        (ctx) => ctx.send('Hello get')
      ))
  ..add(Route(
      'post',
      (ctx) => ctx.send('Hello post'),
      method: HttpMethod.post
      ));

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  les: ^0.0.5

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:les/les.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
48
Learn more about scoring.

We analyzed this package on Jul 17, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.4.0
  • pana: 0.12.19

Platforms

Detected platforms: Flutter, other

Primary library: package:les/les.dart with components: io.

Health suggestions

Fix lib/src/middlewares/cors.dart. (-0.50 points)

Analysis of lib/src/middlewares/cors.dart reported 1 hint:

line 38 col 21: This function has a return type of 'Future

Fix lib/src/middlewares/static_files_handler.dart. (-0.50 points)

Analysis of lib/src/middlewares/static_files_handler.dart reported 1 hint:

line 29 col 21: This function has a return type of 'Future

Maintenance suggestions

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0-dev.9.4 <3.0.0
http_server ^0.9.8 0.9.8+3
path_to_regexp ^0.2.1 0.2.1
Transitive dependencies
mime 0.9.6+3
path 1.6.2
Dev dependencies
test ^1.5.3

Admin