Scouter is a package which was made following the goal to provide a NestJS-like experience to Dart Developers that want to develop Rest APIS

Overview

Scouter is a package which was made following the goal to provide a NestJS-like experience to Dart Developers that want to develop Rest APIS

Features

  • Routing system through annotations
  • Modules
  • Middlewares
  • DI

Getting started

All you need to do is to add the package as a dependency, just like:

dart pub add scouter

Usage

You can check a more complete example in example/scouter_example.dart However, here you can find everything you need to start your application

Initializing your app

You just need to call runServer() function inside main and make your setup, such as:

void main() async{
    final appModule = AppModule(
      modules: [
        TestModule(),
      ],
      middlewares: [
        ExampleMidleware(),
        LoggerMiddleware(),
      ],
      controllers: [
        FeatureController(),
        GameController(),
      ],
    );

    runServer(
        appModule,
        port: 8084,
    );
}

App Module

Your app entrypoint and also main module, will be the AppModule class, which will receive your other Modules. Such as Middlewares, Controllers and Global Middlewares.
Global Middlewares are, in a nutshell, middlewares which will be applied to every single route in your project, whatever the controller that will be wrapping it, or even the module itself. The module preffix for endpoints declared in an app module's controller is "/". You can read more about it below.

Modules

A module is designed to be a context wrapper of your application's business, it was made thinking about ease when talking about domain division. Each module will have their own controllers and middlewares. Scouter also requires a preffix, that will be responsible to mount the url. Usually, the url will follow this model: http://host/Module.preffix/Controller.name/Route. Each module can also have their own middlewares. A module middleware will be applied to every route, inside every controller, declared in this middleware.

class TestModule extends Module {
  TestModule({super.preffix = "teste"});

  @override
  List<RestController> get controllers => [
        GameController(),
        ProfileController(),
      ];

  @override
  List<HttpMiddleware> get middlewares => [];
}

Controllers

Each controller, just like a module, will have a preffix, but the thing about it is that you dont need to explicitly declare it if you dont want to. That's because Scouter can handle the classname itself to compose the preffix. You just need to ensure that your controller contains the word "Controller" on its name, it must be this way. You also must extends RestController class. By default RestController will provide a way to inject and get injectables inside it, it will be clearer below, but for now, it is important to say that DI is made globally, so, you do not need to declare same DI Container twice.

@HttpController()
class ProfileController extends RestController {
  @Get("/:id")
  getById(HttpRequest request) {
    return ResponseSample();
  }

  @Get("/")
  get(HttpRequest request) {
    return ResponseSample();
  }
}

class ResponseSample {
  String message = "Salvo com sucesso!";
  int savedId = 70;
  int httpStatus = 206;
}

Following the sample above, the endpoint declared on the "getById" method would be: http://host/somemodule/profile/private. If you want to change the controller preffix, you can just do the following:

@HttpController(name: "pro")
class ProfileController extends RestController {
...

Which would result in the given url for same endpoint above: http://host/somemodule/pro/private

Routes

Now, talking about routes, you just need to give the desired http verb annotation to a Controller method. such as:

@HttpController()
class ProfileController extends RestController {
  @Get("/")
  get(HttpRequest request) {
    ...
  }

  @Post("/")
  save(HttpRequest request) {
    ...
  }
}

You can declare dynamic routes this way:

  @Get("/:id")
  getById(HttpRequest request) {
    final id = request.params!["id"];
    ...
  }

Response parsing

Routes can have a return type of HttpResponse itself, but it also supports a Map or even a CustomClass. The best part of using a custom class is that you will not need to parse it to a Map, Json or whatever. For example, if you try to return the following object from a route:

class Profile  {
  final int id = 1;
  final String name = "Anything";
  final List<String> tags = ["cool guy", "developer"];
  final String url = "https://pub.dev";
}

Scouter will parse it to the following format:

{
  "id": 1,
  "name" : "Anything",
  "url": "https://pub.dev",
  "tags" : [
    "cool guy",
    "developer",
  ]
}

This method will not parse any method that your class may contain.
Also, if you prefer, you can return a class which contains one of the following methods: toJson() or toMap(). Both should return a Map of String,dynamic. Just like this:

class Profile  {
  final int id = 1;
  final String name = "Anything";
  final List<String> tags = ["cool guy", "developer"];
  final String url = "https://pub.dev";

  Map<String,dynamic> toMap() => {
    "name" : name,
    "tags" : tags,
    "url" : url,
  };
}

As you can see, you can ommit and apply whatever logic you want to compose your map, it is important that in the typing, the subtypes of entry, for the parsed map, to be declared, it may always be String and dynamic.

By default, status 200 will be applied to response, but, if you are returning an object that will be parsed, just like above, you can set it through httpStatus property, which needs to be an int. It will be applied to the final response. Such as:

class Profile  {
  final int id = 1;
  final String name = "Anything";
  final List<String> tags = ["cool guy", "developer"];
  final String url = "https://pub.dev";
  final int httpStatus = 201;
}

It is important to notice that:

  • variables from custom objects will be parsed exactly how it is declared, soon, a way to customize the desired key will be introduced, but for now, if you declare something like this:

    class Profile  {
      final int idUser = 5;
    }

    It will be parsed to this:

    {
      "idUser" : 5
    }
  • if you are using the toMap() or toJson() methods, no processing will be made in your instance, instead, this methods will be called, just the way you implemented it

  • no methods will be parsed, it includes getters.

You Must start the route with "/", otherwise an exception will be thrown when trying to run the server;
You Must return something from your route, otherwise it will cause a timeout exception

Middlewares

As said above, you can define middlewares to the whole application through your AppModule. Also, you can define it to a single module, including all of its children. The same as Controllers.
A Middleware is nothing but a class which implements the HTTP Middleware interface. It just need to contains a handle(HttpRequest request) method, which MUST return a:

Future<Either<HttpResponse, void>> handle(HttpRequest request)

So, if you are not used to Either return, it is basically a way to have two return types, a Left and a Right. Left would be a case when you dont want to proceed in your logic flow, and handle it as a exception, or something like this. Right would be the opposite.
So, knowing that, basically, you will want to return a HttpResponse if you do not want the request to going further in your api. Otherwise, you can just return a Right() with a null, for example.
It is importat to say that Scouter's uses FPDart package, which exports some functional programming stuff, thats where this Either comes from. If you want to, there is no need to add fpdart to your project, once Scouter does exports it too.
Example of middleware:

class ExampleMidleware implements HttpMiddleware {
  const ExampleMidleware();
  @override
  Future<Either<HttpResponse, void>> handle(HttpRequest request) async {
    if (request.path.contains("/game")) {
      return Left(
        HttpResponse(
          status: 400,
          body: {"status": "/game is not available"},
        ),
      );
    }
    return Right(null);
  }
}

Thats how you add middlewares to your module:

class TestModule extends Module {
  TestModule({super.preffix = "teste"});

  @override
  List<RestController> get controllers => [
        GameController(),
        ProfileController(),
      ];

  @override
  List<HttpMiddleware> get middlewares => [
    ExampleMidleware(),
  ];
}

And that is how you add middlewares to your controller:

@HttpController(
  middlewares: [
    ExampleMidleware(),
  ],
)
class GameController extends RestController {
  @Get("/")
  HttpResponse getById(HttpRequest request) {
    return HttpResponse(
      body: {"game": "Mario"},
      status: 202,
    );
  }
}

DI

As saied above, RestControllers already have a DI system, which is provided through the Injectable mixin. You can apply it whatever you want to.
Scouter's DI uses a Kiwi implementation, but the injection system is abstracted, soon, it will be possible to choose and implement the DI System you want to. But for now, if you want to use Scouter's, you just need to the following:

@HttpController()
class FeatureController extends RestController {
  FeatureController() {
    inject<FakeProvider>(
      SingletonInjection(
        FakeProvider(),
      ),
    );
  }

  @Post("/save")
  HttpResponse save(HttpRequest request) {
    final FakeProvider teste = injected();
    return HttpResponse(
      body: {
        "teste": teste.name,
      },
    );
  }
}

So, inject will be responsible for saving your container, and will receive a injection, which can be a SingletonInjection or a FactoryInjection. So, inside <>() you just put the type you want to attribute to your container and voilà, the magic is done.

And if you want to apply Scouter's DI to anywhere else in your project, you can just do the following:

import "package:scouter/scouter.dart";
class MyOwnClass with Injectable{
}

Through this, you will can use the inject and injected functions.

Compile & Deploy

So, because of Scouter depends on dart:mirrors, it cannot be compiled as an AOT, because the lack of support to Runtime. So, you should compile it as a Kernel Module:

dart compile kernel bin/your_app.dart

It will result in a ".dill" file, which you can run through:

dart run bin/your_app.dill

For deploying it is recommended to use a docker container, which, unfortunately, will need to have Dart installed on it. You can use something like this .Dockerfile

FROM dart:stable AS build

WORKDIR /app

COPY pubspec.* ./
RUN dart pub get

COPY . 

RUN dart pub get --offline
RUN dart compile kernel bin/server.dart -o bin/server

Expose 3000
CMD ["dart", "run", "bin/server"]

We are aware that this is not the best experience for deploying purposes, specially when talking about the container size due to the need of Dart. Soon We'll be trying to provide a better experience.

You might also like...

Maps for Flutter developers. Supports Apple, Bing, and Google APIs.

Overview Cross-platform geographic maps for Flutter applications. Pull requests are welcome! The packages are licensed under the Apache License 2.0. P

Oct 13, 2022

Flutter package that provide selectable items in list like Column

Flutter package that provide selectable items in list like Column

vertical_picker vertical_picker is flutter package that you can use it as item selector. users with this package be able to select item that is in ver

Nov 19, 2022

DEVS: Developer Board and Jobs Listing | For Developers, By Developers

DEVS: Developer Board and Jobs Listing | For Developers, By Developers

devs Setup Currently, this DEVS project is using the master channel of the Flutter SDK. TODO: Migrate to beta Clone the project git clone https://gith

Apr 16, 2022

Flutter-Shared-Preference - The goal is to learn how to use the shared preferences plugin to save important pieces of information to your device.

Flutter-Shared-Preference - The goal is to learn how to use the shared preferences plugin to save important pieces of information to your device.

Recipe Finder The goal is to learn how to use the shared preferences plugin to save important pieces of information to your device. Final App UI Resou

Jan 1, 2022

An app to save money and achieve your goal! Available on iOS & Android 🚀

An app to save money and achieve your goal! Available on iOS & Android 🚀

BudgetMe An app that helps you save money and achieve your goal! Screenshots TestFlight & Google Play Beta License About This is an app to save money

Nov 27, 2022

A smartphone application called Easy Job goal is to make easier for businesses to find people who meet their standards as well as for job seekers to search for and choose from available positions .

Easy_Jobs 19SW54(MAD-Project) A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to ge

Nov 6, 2022

A flutter package that developers have pretty logs instead just printing everything like a newbie

A flutter package that developers have pretty logs instead just printing everything like a newbie. Features Makes it easy to log to console without us

Nov 28, 2021

Magpie is a visualized platform which designed to create, develop and compile your standalone flutter module.

Magpie is a visualized platform which designed to create, develop and compile your standalone flutter module.

Magpie Workflow is a visualized platform which is designed to create, develop and compile your standalone flutter module;

Dec 4, 2022

Movies4u app UI is simple enough to use and the app is a fun way to get an overview of your movie experience. This repo created with help of awesome UI, material Design and latest feature. this repo contain major feature like : dark theme.

Movies4u app UI is simple enough to use and the app is a fun way to get an overview of your movie experience. This repo created with help of awesome UI, material Design and latest feature. this repo contain major feature like : dark theme.

Moviesfree4U This is simple repository, that help in fetch latest, upcomming movies. Website https://movies4u-ef56f.firebaseapp.com/#/ https://movies4

Dec 10, 2022
Owner
Vinicius Amélio
Desenvolvedor de Software Pleno
Vinicius Amélio
The FTC Team Scouter App that gets you results developed using a Dart framework

The FTC Team Scouter App that gets you results! Find your perfect alliance by seeing on what their robot can do, and find contact details all from right in the app! Great UI interfaces, Animations and more make it the perfect app for you

Siddharth Ray 2 May 31, 2022
DoIt is an Mobile Application which helps us to be productivity by challenging yourself with others on a specific goal.

challengeapp A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if

Pratik JH 0 Dec 26, 2021
A library for building REST APIs easily with Dart

A library for building REST APIs easily with Dart modeled after Express JS for Node Js. The library is still a work in progress and open to contributi

Albert Oboh 43 Oct 4, 2022
Backbone - A Dart framework for writing REST APIs from an Open API spec

The Backbone Dart Backend Framework A Dart framework for writing REST APIs from

Marcus Twichel 39 Oct 6, 2022
A project made for the ECV Digital 2022. 🌐 The goal being to make a Flutter application to connect, register and display information of a given API.👨🏼🔧

not_netflix A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if t

QUENEL Laurent 2 May 7, 2022
A mobile client for the public apis repository, 1400+ free apis to use able to be navigated through your phone :)

Public APIs mobile app Your assistant app that will help you discover and pick the next API for your next development project What it contains, you sa

Gwhyyy 4 Dec 25, 2022
flutter_thrio makes it easy and fast to add flutter to existing mobile applications, and provide a simple and consistent navigator APIs.

中文文档 英文文档 问题集 原仓库不再维护,代码已经很老了 最近版本更新会很快,主要是增加新特性,涉及到混合栈的稳定性的问题应该不多,可放心升级,发现问题加 QQ 群号码:1014085473,我会尽快解决。 不打算好好看看源码的使用者可以放弃这个库了,因为很多设定是比较死的,而我本人不打算花时间写

null 290 Dec 29, 2022
flutter_thrio makes it easy and fast to add flutter to existing mobile applications, and provide a simple and consistent navigator APIs.

本仓库不再维护,可移步新仓库 https://github.com/flutter-thrio/flutter_thrio 中文文档 问题集 QQ 群号码:1014085473 The Navigator for iOS, Android, Flutter. Version 0.2.2 requir

Hellobike 732 Dec 5, 2022
Flet enables developers to easily build realtime web, mobile and desktop apps in Python. No frontend experience required.

Flet Flet is a framework that enables you to easily build realtime web, mobile and desktop apps in your favorite language and securely share them with

Flet 3.6k Jan 9, 2023
Flet enables developers to easily build realtime web, mobile and desktop apps in Ruby. No frontend experience required

Flet If bundler is not being used to manage dependencies, install the gem by executing: $ gem install flet Flet Flet is a framework that enables you

AdamMusa 29 Jan 3, 2023