Sparky: A Lightweight Framework for Building REST and WebSocket APIs with JWT Authentication

Published on by Flutter News Hub

Sparky: A Lightweight Framework for Building REST and WebSocket APIs with JWT Authentication

Sparky is a Dart package that simplifies the development of RESTful and WebSocket APIs with support for JWT authentication. It offers a range of features to enhance the development process.

Features

  • Comprehensive logging system
  • WebSocket support
  • JWT authentication
  • Customizable pipelines for pre- and post-processing of requests and responses

Creating Routes

Creating a Simple Route

Using a custom route constructor, you can specify the HTTP method or use the default constructor and customize the route later.

import 'package:sparky/sparky.dart';

void main() {
  // Create a route with a custom middleware that accepts all request data and returns a response.
  final route1 = RouteHttp.get('/test', middleware: (request) async {
    return Response.ok(body: 'Hello, world!');
  });

  // Initialize Sparky with a list of routes.
  Sparky.server(routes: [route1]);
}

Creating a Route from a Class

Routes can also be created as classes, providing more control over the route's behavior and configuration, such as WebSocket support and accepted HTTP methods.

import 'package:sparky/sparky.dart';

class RouteTest extends Route {
  RouteTest() : super('/test', middleware: (request) async {
    return Response.ok(body: 'test');
  }, acceptedMethods: [AcceptedMethods.get, AcceptedMethods.post]);
}

class RouteSocket extends Route {
  RouteSocket() : super('/socket', middlewareWebSocket: (WebSocket webSocket) async {
    webSocket.listen((event) {
      print(event);
    }, onDone: () {
      webSocket.close();
    });
  });
}

void main() {
  // Initialize Sparky with a list of routes.
  Sparky.server(routes: [RouteTest(), RouteSocket()]);
}

Customizing IP and Port

You can specify the IP address and port used by Sparky.

void main() {
  Sparky.server(routes: [...], ip: '0.0.0.0', port: 8080);
}

Creating Pipelines

Pipelines allow you to add middleware to be executed before or after the main route middleware.

void main() {
  Sparky.server(
    routes: [...],
    // Executes after the route middleware.
    pipelineAfter: Pipeline()..add((request) async => null)..add((request) async => null),
    // Executes before the route middleware.
    pipelineBefore: Pipeline()..add((request) async { ... }),
  );
}

Logging System

Sparky provides a configurable logging system.

void main() {
  Sparky.server(
    routes: [...],
    logConfig: LogConfig.showAndWriteLogs,
    logType: LogType.all
  );
}

Using WebSockets

WebSocket routes can be created with the RouteWebSocket class and added to the list of routes.

void main() {
  final websocket = RouteWebSocket(
    '/test',
    middlewareWebSocket: (WebSocket socket) async {
      socket.add('Hello, world!');
      socket.listen((event) {
        print(event);
      }, onDone: () {
        socket.close();
      });
    },
  );

  Sparky.server(routes: [websocket]);
}

Implementing JWT Authentication

Using JWT authentication, you can protect routes by verifying a token sent in the request.

import 'package:sparky/sparky.dart';

void main() {
  final authJwt = AuthJwt(secretKey: 'secretKey');

  final login = RouteHttp.get('/login', middleware: (HttpRequest request) async {
    final token = authJwt.generateToken({'username': 'username'});
    return Response.ok(body: '{"token":"$token"}');
  });

  Sparky.server(
    routes: [login],
    pipelineBefore: Pipeline()
      ..add((HttpRequest request) async {
        if (request.requestedUri.path == '/login') {
          return null;
        } else {
          if (request.headers['token'] != null) {
            if (authJwt.verifyToken(request.headers['token']!.first)) {
              return null;
            } else {
              return Response.unauthorized(body: 'Unauthorized');
            }
          } else {
            return Response.unauthorized(body: 'Send token in the header');
          }
        }
      }),
  );
}

Performance Optimization

For improved performance, compile your Dart code to an executable using the following command:

dart compile exe main.dart

Future Vision

Sparky aims to remain simple and user-friendly. Future updates will focus on adding support for executing specific routes in separate isolates for enhanced performance. Contributions to the open-source project are always welcome.

Flutter News Hub