Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/khode-io/nest-dart/llms.txt

Use this file to discover all available pages before exploring further.

Dart Frog Integration

The nest_frog package brings Nest Dart’s modular architecture to Dart Frog, enabling clean, maintainable backend applications with powerful dependency injection.

Installation

Add the dependency to your pubspec.yaml:
dependencies:
  nest_frog: ^latest
  dart_frog: ^latest

Quick Start

1

Create Your Modules

Define modules for different parts of your application:
import 'package:nest_core/nest_core.dart';

class UserModule extends Module {
  @override
  List<Module> get imports => [CoreModule()];

  @override
  Future<void> providers(Locator locator) async {
    locator.registerSingleton<UserService>(
      UserService(locator.get<Database>()),
    );
  }

  @override
  List<Type> get exports => [UserService];
}

class CoreModule extends Module {
  @override
  Future<void> providers(Locator locator) async {
    locator.registerSingleton<LoggerService>(LoggerService());
    locator.registerSingleton<Database>(Database());
  }

  @override
  List<Type> get exports => [LoggerService, Database];
}
2

Create App Module

Create a root module that imports all feature modules:
import 'package:nest_core/nest_core.dart';

class AppModule extends Module {
  @override
  List<Module> get imports => [
    DatabaseModule(),
    CoreModule(),
    UserModule(),
  ];

  @override
  Future<void> providers(Locator locator) async {}
}
3

Setup Middleware

Add the Nest Frog middleware in routes/_middleware.dart:
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';
import 'package:your_app/app_module.dart';

Handler middleware(Handler handler) {
  return handler.use(nestFrogMiddleware(AppModule()));
}
4

Use Services in Route Handlers

Access your services in route handlers:
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';

Future<Response> onRequest(RequestContext context) async {
  final modular = Modular.of(context);
  final userService = modular.get<UserService>();
  final logger = modular.get<LoggerService>();

  logger.log('Users route accessed');

  final users = userService.getAllUsers();
  return Response.json(body: {'users': users});
}

Modular API

The Modular class provides unified access to your dependency injection container.

Initialize Container

Initialize the application container with your root module:
import 'package:nest_frog/nest_frog.dart';

Handler middleware(Handler handler) {
  if (!Modular.isInitialized) {
    Modular.initialize(AppModule());
  }

  return handler.use(nestFrogMiddleware(AppModule()));
}
The middleware automatically calls Modular.initialize() if not already initialized, but you can also do it manually for more control.

Access Services

There are two ways to access services:
final modular = Modular.of(context);
final userService = modular.get<UserService>();
final logger = modular.get<LoggerService>();
The context-based approach (Modular.of(context)) is recommended as it integrates with Dart Frog’s request context and can utilize context-specific providers.

Middleware Setup

The nestFrogMiddleware function creates a middleware that initializes and provides access to your dependency injection container.
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';

Handler middleware(Handler handler) {
  return handler
      .use(nestFrogMiddleware(AppModule()))
      .use(provider<String>((context) => 'Welcome Message'));
}

How It Works

  1. Checks if the container is initialized
  2. If not, calls Modular.initialize() with your app module
  3. Waits for all services to be ready
  4. Makes services available to route handlers

Route Handlers

Access services in your route handlers using the Modular.of(context) API:

GET Request Example

import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';

Future<Response> onRequest(RequestContext context) async {
  final modular = Modular.of(context);
  final userService = modular.get<UserService>();
  final logger = modular.get<LoggerService>();

  logger.log('Users route accessed');

  switch (context.request.method) {
    case HttpMethod.get:
      return _getUsers(userService);
    case HttpMethod.post:
      return await _createUser(context, userService);
    default:
      return Response(statusCode: 405, body: 'Method not allowed');
  }
}

Response _getUsers(UserService userService) {
  final users = userService.getAllUsers();

  return Response.json(
    body: {
      'users': users.map((user) => user.toJson()).toList(),
      'count': users.length,
      'timestamp': DateTime.now().toIso8601String(),
    },
  );
}

POST Request Example

Future<Response> _createUser(
  RequestContext context,
  UserService userService,
) async {
  try {
    final body = await context.request.json() as Map<String, dynamic>;
    final name = body['name'] as String?;
    final email = body['email'] as String?;

    if (name == null || email == null) {
      return Response.json(
        statusCode: 400,
        body: {
          'error': 'Missing required fields',
          'message': 'Both name and email are required',
        },
      );
    }

    final user = userService.createUser(name, email);
    return Response.json(
      statusCode: 201,
      body: {
        'message': 'User created successfully',
        'user': user.toJson(),
        'timestamp': DateTime.now().toIso8601String(),
      },
    );
  } catch (e) {
    return Response.json(
      statusCode: 400,
      body: {
        'error': 'Invalid request body',
        'message': 'Request body must be valid JSON',
      },
    );
  }
}

Dynamic Routes

Access path parameters in dynamic routes:
// routes/users/[id].dart
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog/nest_frog.dart';

Future<Response> onRequest(RequestContext context, String id) async {
  final modular = Modular.of(context);
  final userService = modular.get<UserService>();

  final userId = int.tryParse(id);
  if (userId == null) {
    return Response.json(
      statusCode: 400,
      body: {'error': 'Invalid user ID'},
    );
  }

  final user = userService.getUserById(userId);
  if (user == null) {
    return Response.json(
      statusCode: 404,
      body: {'error': 'User not found'},
    );
  }

  return Response.json(body: user.toJson());
}

Complete Example

Here’s a complete example of a Dart Frog application with Nest Dart:
import 'package:dart_frog/dart_frog.dart';
import 'package:nest_frog_backend/app_module.dart';
import 'package:nest_frog/nest_frog.dart';

Handler middleware(Handler handler) {
  if (!Modular.isInitialized) {
    Modular.initialize(AppModule());
  }

  return handler.use(nestFrogMiddleware(AppModule()));
}

Testing

Reset the container between tests:
import 'package:nest_frog/nest_frog.dart';
import 'package:test/test.dart';

void main() {
  setUp(() async {
    await Modular.reset();
    await Modular.initialize(AppModule());
  });

  tearDown(() async {
    await Modular.reset();
  });

  test('user service returns users', () async {
    final userService = Modular.get<UserService>();
    final users = userService.getAllUsers();
    expect(users, isNotEmpty);
  });
}

Container Status

Check the container initialization status:
// Check if initialized
if (Modular.isInitialized) {
  print('Container is ready');
}

// Wait for container to be ready
await Modular.container.waitUntilReady();

// Check if specific service is ready
final isReady = Modular.container.isReady;

Best Practices

  • Initialize the container once in your root middleware
  • Use Modular.of(context) for accessing services in route handlers
  • Organize related services into feature modules
  • Export only the services that other modules need
  • Reset the container in tests for isolation

Advanced: Direct Container Access

For advanced use cases, you can access the underlying container:
import 'package:nest_frog/nest_frog.dart';

// Get the container instance
final container = Modular.container;

// Wait until all services are ready
await container.waitUntilReady();

// Get available services
final services = container.getAvailableServices();
print('Available services: $services');

See Also

Build docs developers (and LLMs) love