Fennec is a dart web framework with the principal goal: make web server side more easy and fast to develop.

Packages

Packages pub
fennec (core framework) fennec
fennec_pg fennec_pg
fennec_jwt fennec_jwt

installation:

  1. create a simple dart project. you can use terminal for that dart create 'projectname'
  2. install the framework from pub.dev

make your first request:

create your First RestController:

@RestController(path: '/example')
class Test {
  @Route('/test', RequestMethod.get())
  Future test(Request request, Response response) async {
    response.send('hello world');
  }

  @AuthenticatedRoute('/template', RequestMethod.get(), MiddlewareHanlderImpl())
  Future testMiddleWare(Request request, Response response) async {
    response.render('template.html');
  }

  @AuthorizatedRoute('/authorization', RequestMethod.get(),
      MiddlewareHanlderImpl(), ['ADMIN'], UserProviderImpl())
  Future testAuthorization(Request request, Response response) async {
    response.render('template.html');
  }
}

Fennec Framework has three types of Routing:

  • Route is simple Route without any post executions or middlewares before the request will be executed.
  • AuthenticatedRoute is a Route that required also a milldware class where the deveveloper can define all Operations and Middlwares (for example authenticate the token) that must be executed before the request will be executed.
  • AuthorizatedRoute is a Route that required also a milldware and class for Authorizate the user and a List of Roles of user that can use this request. this Route will typically used for softwares with many roles of users.

Middleware

it must be a subtype of the class MiddlewareHandler , here an example how to implement it:

class MiddlewareHanlderImpl extends MiddlewareHandler<MiddlewareHanlderImpl> {
  const MiddlewareHanlderImpl();
  @Middleware(priority: 0)
  Future<MiddleWareResponse> test(Request request, Response response) async {
    if (1 == 1) {
      return MiddleWareResponse(MiddleWareResponseEnum.next);
    }
    response.badRequest().send('not allowed second');
    return MiddleWareResponse(MiddleWareResponseEnum.stop);
  }

  @Middleware(priority: 1)
  Future<MiddleWareResponse> test1(Request request, Response response) async {
    if (1 == 1) {
      return MiddleWareResponse(MiddleWareResponseEnum.next);
    }
    response.badRequest().send('not allowed first ');
    return MiddleWareResponse(MiddleWareResponseEnum.stop);
  }
}

every Middlware inside the class must be annotated with @Middleware() and have this signature Future

UserProvider

UserProvider is an interface that contains the function loadUser based and the request data and Roles used on the AuthorizatedRoute

Example of implementation of UserProvider

class UserProviderImpl extends UserProvider {
  const UserProviderImpl();
  @override
  @AuthorizationRequired()
  Future<UserDetails?> loadUser(
      Request request, Response response, List<String> roules) async {
    if (!roules.contains('element')) {
      response.forbidden().send('not allowed');
      return null;
    }
    return UserDetailsImpl(1, 'tester', '1@web.de', '123456', []);
  }

class UserDetailsImpl extends UserDetails {
  UserDetailsImpl(id, String username, String email, String password,
      Iterable<Object> authorities)
      : super(id, username, email, password, authorities);

  @override
  UserDetails fromJson(Map<String, dynamic> map) {
    // TODO: implement fromJson
    throw UnimplementedError();
  }

  @override
  bool isAccountNonExpired() {
    // TODO: implement isAccountNonExpired
    throw UnimplementedError();
  }

  @override
  bool isAccountNonLocked() {
    // TODO: implement isAccountNonLocked
    throw UnimplementedError();
  }

  @override
  bool isCredentialsNonExpired() {
    // TODO: implement isCredentialsNonExpired
    throw UnimplementedError();
  }

  @override
  bool isEnabled() {
    // TODO: implement isEnabled
    throw UnimplementedError();
  }
}

dynamic routes

here is an example hot to use dynamic routes

@Route('/dynamic_route/@user_id/@doc_id', RequestMethod.get())
Future dynamicRoutes(Request request, Response response) async {
    response.json({
      'userId': request.pathParams!['user_id'],
      'docId': request.pathParams!['doc_id']
    });
  }

File System Routing

an example how to handle files


@Route('/files', RequestMethod.get())
Future fileSystems(Request request, Response response) async {
    response.json({
      'file1': request.files.first.toString(),
    });
}

WebSocket

WebSocket is already integrated in the core of Framework.

how to use it :


WebSocketHandler webSocketHandler = WebSocketHandler();
webSocketHandler.registerWebSocketHandler(server);
webSocketHandler.clientsListener.stream.listen((event) {
    if (event.headers!.value('token') != null) {
      webSocketHandler.addClient(event);
    } else {
      event.webSocket.addError('not allowed');
    }
  });
//Send data to all registred Clients
webSocketHandler.sendToAllJson({'key': 'value'});

Multithreading

Fennec Framework supports also Multithreading over isolates. To increate the number of used isolates just call the function setNumberOfIsolates. the default number of isolates is 1

example


applicationCofiguration.setNumberOfIsolates(1);

Start your Server and test your first Request

import 'package:fennec/fennec.dart';
import 'package:path/path.dart' as path;

import 'test.dart';

void main(List<String> arguments) async {
ApplicationConfiguration applicationCofiguration = ApplicationConfiguration();
  applicationCofiguration
      .addControllers([Test])
      .setPort(8000)
      .setHost(InternetAddress.loopbackIPv4);

  Application application = Application(applicationCofiguration);
  Server server = Server(application);
  await server.startServer();
}

deploy

License

MIT

Libraries

fennec
Fennec is a dart web framework with the principal goal make web server side more easy and fast to develop.