CodeBlanks Logo Icon CodeBlanks

Putting it together

Combine all layers into a working mini service.

Integration with the App class

In the final step we bring all parts together. The App class takes a TaskService and returns a summary of all services with the summary() method. This is the last link of dependency injection.

Example: class App { final TaskService svc; App(this.svc); String summary() { return 'Integration: ${svc.list().length} task, fib(10): ${fib(10)}'; } }. App brings the service and the computation function together. In main it is created with App(InMemoryTaskService()). In this project chain we gathered the Shelf API, the sqflite database and the Isolate computation under the same interface; each part was added on top of the previous one.

The summary method

The summary() method returns the application state as a single string. It combines the task count with svc.list().length and the computation result with fib(10). This is where the integration is verified.

Example: String summary() { return 'Integration: ${svc.list().length} task, fib(10): ${fib(10)}'; }. In main it is printed with print(app.summary()). The output is Integration: 1 task, fib(10): 55. This is deterministic; it gives the same result every run. The layers we built throughout the project (model, service, API, database, isolate) merge into a single summary here.

Practice The App class and integration

Write class App with a final TaskService svc field, an App(this.svc) constructor and a String summary() method. Inside summary do return 'Integration: ${svc.list().length} task, fib(10): ${fib(10)}';. In main add final app = App(InMemoryTaskService()); and print(app.summary()).

Starter code

main.dart
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:isolate';

class Task {
  final int id;
  final String title;
  Task({required this.id, required this.title});
}

abstract class TaskService {
  List<Task> list();
}

class InMemoryTaskService implements TaskService {
  @override
  List<Task> list() => [Task(id: 1, title: 'task 1')];
}

Response taskHandler(Request req, TaskService svc) {
  return Response.ok('tasks: ${svc.list().length}');
}

class SqliteTaskService {
  final Database db;
  SqliteTaskService(this.db);

  Future<List<Task>> all() async {
    final rows = await db.query('tasks');
    return rows.map((r) => Task(id: r['id'] as int, title: r['title'] as String)).toList();
  }
}

int fib(int n) {
  if (n < 2) return n;
  return fib(n - 1) + fib(n - 2);
}

Future<int> heavyCompute(int n) {
  return Isolate.run(() => fib(n));
}

// write the App class (takes TaskService, summary method)
// create App in main and print summary

void main() {
  // print summary with App
}

Sample solution

main.dart
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:isolate';

class Task {
  final int id;
  final String title;
  Task({required this.id, required this.title});
}

abstract class TaskService {
  List<Task> list();
}

class InMemoryTaskService implements TaskService {
  @override
  List<Task> list() => [Task(id: 1, title: 'task 1')];
}

Response taskHandler(Request req, TaskService svc) {
  return Response.ok('tasks: ${svc.list().length}');
}

class SqliteTaskService {
  final Database db;
  SqliteTaskService(this.db);

  Future<List<Task>> all() async {
    final rows = await db.query('tasks');
    return rows.map((r) => Task(id: r['id'] as int, title: r['title'] as String)).toList();
  }
}

int fib(int n) {
  if (n < 2) return n;
  return fib(n - 1) + fib(n - 2);
}

Future<int> heavyCompute(int n) {
  return Isolate.run(() => fib(n));
}

class App {
  final TaskService svc;
  App(this.svc);

  String summary() {
    return 'Integration: ${svc.list().length} task, fib(10): ${fib(10)}';
  }
}

void main() {
  final app = App(InMemoryTaskService());
  print(app.summary());
}

Expected output

Integration: 1 task, fib(10): 55

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 The App service field

Question
class App {
  final ____ svc;
  App(this.svc);
}
Answer
class App {
  final TaskService svc;
  App(this.svc);
}

Explanation: the App class takes a TaskService.

2 Match the integration parts

Term Meaning
App Application
summary Summary
TaskService Service
fib Fibonacci

3 What does App.summary do?

  • Encrypts
  • Compresses
  • Returns a summary Correct answer
  • Serializes

Explanation: App.summary returns a summary of the application.

All lessons in Advanced