shade 0.1.4

  • Readme
  • Changelog
  • Example
  • Installing
  • 57

shade #

A fast and flexible Microservice oriented HTTP server framework for dart.

Installing #

Depend on it #

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

dependencies:
  shade: ^0.1.3

Install it #

You can install packages from the command line:

with pub:

pub get

Import it #

Now in your Dart code, you can use:

import 'package:shade/shade.dart';

Dependency Injection #

Shade has a buil-in flexible dependency injector. Using the Injectable annotation you can define the name of the constructor that is being injected into.

abstract class Service {
    ...
}

abstract class ImplementationOfService extends Service {
    ...
}

@Injectable()
@Controller()
class ExampleController {

    final Service service;

    const ExampleController(@Inject("TokenForService") this.service);

    @Get("/example")
    void getExample(Request req, Response res, Step step) {
        ...
    }
}

Routing #

Routing in shade is simple and flexible. Enables the quick addition of endpoints.

@Controller("/someBasePath")
class ExampleController {
    ...

    @Get("/example")
    void getExample(State state, Request req, Response res, Step step) {
        ...
    }

    @Post("/:echoMessage") // Path parameter
    void getEcho(State state, Request req, Response res, Step step) {
        ...
    }

    @Get("/example/*") // Catch all
    void getEcho(State state, Request req, Response res, Step step) {
        ...
    }
}

Middleware #

Middleware is execution of Application level middleware -> Controller level middleware -> Route level middleware. On each of these levels middleware is executed in order of addition/annotation and determined to be executed before or after the endpoint by being annotated or added as Preware for before and Postware for after.

You can define Middleware to be a single function or as an instance of Middleware. Functional middleware is static where as instances of Middleware can have dependencies injected into them or can be instantiated manually when annotated or added with parameters.

Functional Middleware #

void middlewareFunc(Request req, Response res, Step step) {
    state.putLocal("local", "some value for local.");
    step(); // Moves to next RouteStep
}

Instance of Middleware #

// Middleware as with dependency injection.
@Injectable()
class SomeMiddleware extends Middleware {

    final Service service;

    const SomeMiddleware(@Inject("TokenForService") this.service);

    @override
    void step(Request req, Response res, Step step) {
        int someValue = this.service.calculate();
        state.putLocal("local", someValue);
        step(); // Moves to next RouteStep
    }
}

// Parameterized middleware.
class SomeOtherMiddleware extends Middleware {

    final String parameter;

    const SomeMiddleware(this.parameter);

    @override
    void step(Request req, Response res, Step step) {
        state.putLocal("local", this.parameter);
        step(); // Moves to next RouteStep
    }
}

Annotating and Adding Middleware #


// Controller and Route level.
@Controller()
@Preware(middleware) // Execute middleware just before this all endpoints in this Controller
@Postware(SomeMiddleware) // Execute middleware right after all endpoints in this Controller
class ExampleController {

    @Get("/example")
    @Postware(SomeMiddleware) // Execute middleware right after this endpoint
    @Preware([middleware, SomeOtherMiddleware("someParameter")]) // Execute all middleware in order just before this endpoint
    void getExample(Request req, Response res, Step step) {
        ...
    }

}

// Application level.
void main() {
    var appBuilder = ApplicationBuilder()
        ...
        ..addPreware(SomeOtherMiddlware("anotherParameter"))
        ..addPostware(middleware);
        ...
}

Build an Application #

Shade has an ApplicationBuilder class that allows you to add Controllers, set an ErrorHandler, add Injections, and add Application level Middleware.

Building a simple Application. #

void main() {

    var appBuilder = ApplicationBuilder()
        ..addAllInjections({
            "TokenForService": ImplementationOfService // Define types or instances of types for your injections
        })
        ..addPreware(SomeOtherMiddlware("anotherParameter")) // Execute before all endpoints in the application
        ..addPostware(SomeOtherApplicationMiddleware) // Execute after all endpoints in the application
        ..addAllControllers([
            ExampleController // list of all Controllers in the Application
        ]);

    var app = appBuilder.build();
    app.listen(8000, () => print("Listening on port 8000"));
}

Examples #

See an example in action here.

Changelog #

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[0.1.4] - 2020-05-3 #

Added #

  • Documentation for JsonBodyParser.

Fixed #

  • JsonBodyParser's error handling.

[0.1.3] - 2020-05-2 #

Fixed #

  • Formatting.

Added #

  • Response and State documentation.

[0.1.2] - 2020-05-2 #

Fixed #

  • Package importing and empty list checking.

[0.1.1] - 2020-05-2 #

Fixed #

  • Package formatting.
  • Fix ApplicationCommands not being read by step function.

[0.1.0] - 2020-05-1 #

Initial Release #

example/main.dart

import 'package:shade/shade.dart';

void main() {
  var appBuilder = ApplicationBuilder()
    ..addPreware(JsonBodyParser)
    ..addAllInjections({"PersonService": PrimaryPersonService})
    ..addAllControllers([PersonController]);

  var app = appBuilder.build();
  app.listen(8000, () => print("Listening on port 8000"));
}

// Controller
@Injectable()
@Controller("/person")
@Postware(LogRequest)
class PersonController {
  final PersonService service;

  PersonController(@Inject("PersonService") this.service);

  @Get()
  void getAllPeople(Request req, Response res, Step step) {
    this.service.getAllPeople().then((people) {
      res.sendJson(people);
      step();
    });
  }

  @Post()
  void createPerson(Request req, Response res, Step step) {
    var json = res.state["json"];
    this
        .service
        .createPerson(json["id"], json["name"], json["age"], json["likeToCode"])
        .then((_) {
      res.sendJson({"message": "success!"});
      step();
    }).catchError(step);
  }

  @Get("/:personId")
  void getPerson(Request req, Response res, Step step) {
    var id = int.parse(req.pathParameters["personId"]);
    this.service.getPerson(id).then((person) {
      res.sendJson(person);
      step();
    });
  }

  @Patch("/:personId")
  void patchPerson(Request req, Response res, Step step) {
    var id = int.parse(req.pathParameters["personId"]);
    var json = res.state["json"];
    this
        .service
        .patchPerson(id,
            name: json["name"],
            age: json["age"],
            likesToCode: json["likesToCode"])
        .then((person) {
      res.sendJson({"message": "success!"});
      step();
    });
  }

  @Put("/:personId")
  void putPerson(Request req, Response res, Step step) {
    var json = res.state["json"];
    var id = int.parse(req.pathParameters["personId"]);
    this
        .service
        .putPerson(id, json["name"], json["age"], json["likesToCode"])
        .then((_) {
      res.sendJson({"message": "success!"});
      step();
    });
  }

  @Delete("/:personId")
  void deletePerson(Request req, Response res, Step step) {
    var id = int.parse(req.pathParameters["personId"]);
    this.service.deletePerson(id).then((_) {
      res.sendJson({"message": "success!"});
      step();
    });
  }
}

// Dependencies
abstract class PersonService {
  Future<void> createPerson(int id, String name, int age, bool likesToCode);

  Future<void> deletePerson(int id);

  Future<List<Map<String, dynamic>>> getAllPeople();

  Future<Map<String, dynamic>> getPerson(int id);

  Future<void> patchPerson(int id, {String name, int age, bool likesToCode});

  Future<void> putPerson(int id, String name, int age, bool likesToCode);
}

class PrimaryPersonService implements PersonService {
  Future<void> createPerson(
      int id, String name, int age, bool likesToCode) async {
    people
        .add({"id": id, "name": name, "age": age, "likesToCode": likesToCode});
  }

  Future<List<Map<String, dynamic>>> getAllPeople() {
    return Future.value(people);
  }

  Future<void> deletePerson(int id) async {
    people.removeWhere((person) => person["id"] == id);
  }

  Future<Map<String, dynamic>> getPerson(int id) async {
    return Future.value(people.firstWhere((person) => person["id"] == id));
  }

  Future<void> patchPerson(int id,
      {String name, int age, bool likesToCode}) async {
    var personIndex = people.indexWhere((person) => person["id"] == id);
    if (name != null) {
      people[personIndex]["name"] = name;
    }
    if (age != null) {
      people[personIndex]["age"] = age;
    }
    if (likesToCode != null) {
      people[personIndex]["likesToCode"] = likesToCode;
    }
  }

  Future<void> putPerson(int id, String name, int age, bool likesToCode) async {
    var personIndex = people.indexWhere((person) => person["id"] == id);
    people[personIndex]["name"] = name;
    people[personIndex]["age"] = age;
    people[personIndex]["likesToCode"] = likesToCode;
  }
}

// Logging middleware
void LogRequest(Request req, Response res, Step step) {
  print("----- Logging Request -----");
  print("Path: ${req.path}");
  print("HttpMethod: ${req.method}");
  print("Json Body: ${res.state["json"]}");
  step();
}

// Emulated database
List<Map<String, dynamic>> people = [
  {"id": 1, "name": "Adam Soph", "age": 23, "likesToCode": true},
  {"id": 2, "name": "Joe John", "age": 45, "likesToCode": false},
  {"id": 3, "name": "Emilee Zenko", "age": 21, "likesToCode": true},
  {"id": 4, "name": "Ryan Fitz", "age": 37, "likesToCode": false},
  {"id": 5, "name": "Carmella Zenko", "age": 12, "likesToCode": true}
];

Use this package as a library

1. Depend on it

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


dependencies:
  shade: ^0.1.4

2. Install it

You can install packages from the command line:

with pub:


$ pub get

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

3. Import it

Now in your Dart code, you can use:


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

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

  • Dart: 2.8.4
  • pana: 0.13.13

Analysis suggestions

Package not compatible with SDK flutter

Because it is not compatible with any of the supported runtimes: flutter-native, flutter-web

Package not compatible with runtime flutter-native on android

Because of the import of dart:mirrors via the import chain package:shade/shade.dartpackage:shade/src/http/http.dartpackage:shade/src/http/application.dartpackage:shade/src/utilities/metadata.dartdart:mirrors

Package not compatible with runtime flutter-native on ios

Because of the import of dart:mirrors via the import chain package:shade/shade.dartpackage:shade/src/http/http.dartpackage:shade/src/http/application.dartpackage:shade/src/utilities/metadata.dartdart:mirrors

Package not compatible with runtime flutter-native on linux

Because of the import of dart:mirrors via the import chain package:shade/shade.dartpackage:shade/src/http/http.dartpackage:shade/src/http/application.dartpackage:shade/src/utilities/metadata.dartdart:mirrors

Package not compatible with runtime flutter-native on macos

Because of the import of dart:mirrors via the import chain package:shade/shade.dartpackage:shade/src/http/http.dartpackage:shade/src/http/application.dartpackage:shade/src/utilities/metadata.dartdart:mirrors

Package not compatible with runtime flutter-native on windows

Because of the import of dart:mirrors via the import chain package:shade/shade.dartpackage:shade/src/http/http.dartpackage:shade/src/http/application.dartpackage:shade/src/utilities/metadata.dartdart:mirrors

Package not compatible with runtime flutter-web on web

Because of the import of dart:io via the import chain package:shade/shade.dartpackage:shade/src/http/http.dartpackage:shade/src/http/route_step.dartpackage:shade/src/http/context.dartdart:io

Package not compatible with runtime native-aot

Because of the import of dart:mirrors via the import chain package:shade/shade.dartpackage:shade/src/http/http.dartpackage:shade/src/http/application.dartpackage:shade/src/utilities/metadata.dartdart:mirrors

Package not compatible with runtime web

Because of the import of dart:io via the import chain package:shade/shade.dartpackage:shade/src/http/http.dartpackage:shade/src/http/route_step.dartpackage:shade/src/http/context.dartdart:io

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.7.0 <3.0.0