Skip to main content

The Frontend (Flutter App)

The frontend is a standard Flutter application that communicates with the backend. This section details how to integrate and utilize the flutter_vaden package to streamline development, focusing on dependency injection and API client generation.

Vaden Setup

The flutter_vaden package integrates Vaden's dependency injection and other services into your Flutter app.

Installation

To get started, add the following dependencies to your pubspec.yaml file:

dependencies:
flutter_vaden: ^latest_version # Use the latest version
dio: ^latest_version # Dio is used internally by @ApiClient

dev_dependencies:
vaden_class_scanner: ^latest_version # Use the latest version
build_runner: ^latest_version # Required for code generation

Run flutter pub get to install the dependencies.

Code Generation

Vaden relies on code generation to set up its dependency injection and API clients. Create a build.yaml file in the root of your project with the following content:

targets:
$default:
builders:
vaden_class_scanner|aggregating_vaden_builder:
enabled: true
options:
target: flutter

Then, run the code generator:

dart run build_runner build

This command will generate a file (typically lib/vaden_application.dart or similar, depending on your project structure) that includes a class named VadenApp.

The VadenApp Widget

The generated VadenApp class extends FlutterVadenApplication and is your application's entry point for Vaden's services. You should use this generated VadenApp in your runApp method.

void main() {
runApp(VadenApp(child: const MyApp()));
}

class MyApp extends StatelessWidget {
const MyApp({super.key});


Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

The Application Module

Next, you define a main module for your Flutter application. This module, annotated with @VadenModule, is where you list all the other modules that your application depends on. This typically includes a shared DomainModule (if you have one) and any frontend-specific configuration modules.

([DomainModule, AppConfig])
class AppModule {}

Dependency Injection

flutter_vaden provides a robust dependency injection system.

  • @Configuration(): Used to define configuration classes that provide instances of objects.
  • @Bean(): Marks a method within a @Configuration() class that provides an instance to the injector.
  • @Service(): Marks classes as services. Prefer registering services via their interfaces.
  • @Repository(): Marks classes as repositories. Prefer registering repositories via their interfaces.
  • @Component(): Marks any class that needs to be registered in the dependency injection system.

Accessing Instances in Widgets

You can access registered instances directly in your Flutter widgets using the context.read<T>() extension method.

class MyWidget extends StatelessWidget {
const MyWidget({super.key});


Widget build(BuildContext context) {
// Access a service or API client
final myService = context.read<MyService>();
// ... use myService
return Container();
}
}

Connecting Frontend to Backend with @ApiClient()

flutter_vaden simplifies API interactions using the @ApiClient() annotation, which generates an API client based on an abstract class.

1. Configure HTTP Client Package

First, create a configuration class to provide and configure your client package instance. This is where you set the baseUrl and add any interceptors. In this example we will use Dio as the HTTp client.

()
class DioConfiguration {
()
Dio dio() {
final dio = Dio(BaseOptions(baseUrl: 'http://localhost:8080/api'));
dio.interceptors.add(LogInterceptor(responseBody: true)); // Example interceptor
return dio;
}
}

Make sure to include DioConfiguration in your AppModule if it's not already part of another imported module.

2. Define Your API Client

Create an abstract class annotated with @ApiClient() to define your API endpoints. Vaden's code generator will create an implementation for this interface.

()
abstract class TodoApi {
('/todos')
Future<List<TodoModel>> getAllTodos();

('/todos')
Future<TodoModel> createTodo(() TodoModel todo);

('/todos/{id}')
Future<TodoModel> updateTodo(('id') String id, () TodoModel todo);

('/todos/{id}')
Future<void> deleteTodo(('id') String id);
}

Note: All DTOs (Data Transfer Objects) used as return types or @Body() parameters in your @ApiClient() methods must be annotated with @DTO() within your domain package.

3. Use the API Client in Your UI

Finally, inject and use your generated API client in your Flutter widgets.

class TodoListPage extends StatefulWidget {
const TodoListPage({super.key});


State<TodoListPage> createState() => _TodoListPageState();
}

class _TodoListPageState extends State<TodoListPagen> {
late final TodoApi _todoApi;
late Future<List<TodoModel>> _todosFuture;


void initState() {
super.initState();
_todoApi = context.read<TodoApi>(); // Inject the API client
_loadTodos();
}

void _loadTodos() {
setState(() {
_todosFuture = _todoApi.getAllTodos();
});
}

Future<void> _addTodo() async {
// Example: create a new todo
final newTodo = TodoModel(id: UniqueKey().toString(), title: 'New Task', completed: false);
await _todoApi.createTodo(newTodo);
_loadTodos(); // Refresh the list
}


Widget build(BuildContext context) {
//return ...
}
}