### Flutter App Widget Setup Source: https://pub.dev/packages/florval/example Configures the main MaterialApp widget for the Flutter demo application. This includes setting the title, theme, and the home page. ```dart class DemoApp extends StatelessWidget { final Dio dio; const DemoApp({super.key, required this.dio}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Florval Demo API Example', theme: ThemeData( colorSchemeSeed: Colors.indigo, useMaterial3: true, ), home: DemoHomePage(dio: dio), ); } } ``` -------------------------------- ### Calling the Create Task Mutation Source: https://pub.dev/packages/florval Example of how to call the generated `createTask` mutation and handle the different response types. This demonstrates the pattern for interacting with the mutation and updating the UI based on the result. ```dart final response = await createTask(ref, body: CreateTaskRequest(title: 'New task')); switch (response) { case CreateTaskResponseCreated(:final data) => showTask(data), // data is Task case CreateTaskResponseUnprocessableEntity(:final data) => showErrors(data.errors), case CreateTaskResponseUnauthorized(:final data) => handleAuth(data), case CreateTaskResponseUnknown(:final statusCode) => showError('Error: $statusCode'), } // listTasks and getTask providers are automatically refreshed! ``` -------------------------------- ### Create Task Endpoint Source: https://pub.dev/packages/florval This section details the POST endpoint for creating a task. It includes the OpenAPI specification, the generated client method and mutation helper, and an example of how to use it in your application. ```APIDOC ## POST /tasks ### Description Creates a new task. This operation is part of the client API and also exposed as a mutation helper that automatically invalidates related GET providers upon successful creation. ### Method POST ### Endpoint /tasks ### Request Body - **body** (CreateTaskRequest) - Required - The request body containing the task details. ### Request Example ```json { "title": "New task" } ``` ### Response #### Success Response (201) - **data** (Task) - The created task object. #### Response Example ```json { "id": "123e4567-e89b-12d3-a456-426614174000", "title": "New task", "description": null, "status": "todo", "priority": "medium", "assignee_id": null, "tags": [], "due_date": null, "created_at": "2023-10-27T10:00:00Z", "updated_at": "2023-10-27T10:00:00Z" } ``` #### Error Responses - **401** (UnauthorizedError) - Indicates that the request lacks valid authentication credentials. - **422** (ValidationError) - Indicates that the request payload is invalid. ``` -------------------------------- ### OpenAPI Specification for a GET Endpoint Source: https://pub.dev/packages/florval This OpenAPI specification defines a GET endpoint for retrieving a task by its ID. It includes parameters, and defines success and error responses with corresponding schemas. ```yaml /tasks/{id}: get: operationId: getTask parameters: - name: id in: path required: true schema: { type: string } responses: "200": content: application/json: schema: $ref: "#/components/schemas/Task" "401": content: application/json: schema: $ref: "#/components/schemas/UnauthorizedError" "404": content: application/json: schema: $ref: "#/components/schemas/NotFoundError" ``` -------------------------------- ### POST Endpoint Client and Mutation Source: https://pub.dev/packages/florval Generates a client method for POST requests and a Mutation helper that auto-invalidates related GET providers upon successful creation. This ensures that cached data is refreshed when new data is added. ```dart // clients/tasks_api_client.dart Future createTask({required CreateTaskRequest body}) async { try { final response = await _dio.post('/tasks', data: body.toJson()); return switch (response.statusCode) { 201 => CreateTaskResponse.created(Task.fromJson(response.data)), 401 => CreateTaskResponse.unauthorized(UnauthorizedError.fromJson(response.data)), 422 => CreateTaskResponse.unprocessableEntity(ValidationError.fromJson(response.data)), _ => CreateTaskResponse.unknown(response.statusCode ?? 0, response.data), }; } on DioException catch (e) { /* same routing for error responses */ } } ``` ```dart // providers/tasks_providers.dart final createTaskMutation = Mutation(); Future createTask( MutationTarget ref, { required CreateTaskRequest body, }) async { return createTaskMutation.run(ref, (tsx) async { final client = tsx.get(tasksApiClientProvider); final result = await client.createTask(body: body); ref.container.invalidate(listTasksProvider); // auto-invalidate GET providers ref.container.invalidate(getTaskProvider); return result; }); } ``` -------------------------------- ### Import Florval in Dart Code Source: https://pub.dev/packages/florval/install Import the florval package into your Dart files to start using its functionalities. ```dart import 'package:florval/florval.dart'; ``` -------------------------------- ### Get Non-existent Task Source: https://pub.dev/packages/florval/example Attempts to retrieve a task using an invalid ID to test the 404 Not Found response. Handles success (unexpected), unauthorized, not found, and unknown error responses. ```dart final notFoundResp = await tasksClient.getTask( id: '00000000-0000-0000-0000-000000000000', ); switch (notFoundResp) { case r.GetTaskResponseSuccess(:final data): _log('SUCCESS (unexpected): ${data.title}'); case r.GetTaskResponseUnauthorized(): _log('UNAUTHORIZED'); case r.GetTaskResponseNotFound(:final data): _log('NOT FOUND (expected): ${data.message}'); case r.GetTaskResponseUnknown(:final statusCode, :final body): _log('UNKNOWN: status=$statusCode body=$body'); } ``` -------------------------------- ### Initialize Dio and API Clients with Riverpod Source: https://pub.dev/packages/florval/example Sets up the Dio HTTP client and overrides Riverpod providers with instances of generated API clients. Ensure Dio is configured with the correct base URL and timeouts. ```dart import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'api/generated/api.dart'; import 'api/generated/api_responses.dart' as r; void main() { final dio = Dio( BaseOptions( baseUrl: 'http://localhost:3000', connectTimeout: const Duration(seconds: 30), receiveTimeout: const Duration(seconds: 30), ), ); runApp( ProviderScope( overrides: [ authApiClientProvider.overrideWithValue(AuthApiClient(dio)), tasksApiClientProvider.overrideWithValue(TasksApiClient(dio)), usersApiClientProvider.overrideWithValue(UsersApiClient(dio)), projectsApiClientProvider.overrideWithValue(ProjectsApiClient(dio)), notificationsApiClientProvider .overrideWithValue(NotificationsApiClient(dio)), uploadsApiClientProvider.overrideWithValue(UploadsApiClient(dio)), ], child: DemoApp(dio: dio), ), ); } ``` -------------------------------- ### Initialize Florval Configuration Source: https://pub.dev/packages/florval Run the florval init command to create a florval.yaml config file. This file is used to configure the OpenAPI schema path and other generation settings. ```bash dart run florval init ``` -------------------------------- ### Florval CLI Commands Source: https://pub.dev/packages/florval Common florval CLI commands for initialization, generation, and watch mode. Includes options for custom configuration and verbose output. ```bash dart run florval init # Create florval.yaml template dart run florval init --config custom.yaml --force # Custom config path dart run florval generate # Generate from florval.yaml dart run florval generate --watch # Watch mode dart run florval generate --schema api.yaml --output lib/api/ dart run florval generate --verbose # Debug output ``` -------------------------------- ### List Projects with Nested Objects Source: https://pub.dev/packages/florval/example Fetches a list of projects, demonstrating how to access nested objects like owner details and member counts. Handles success, unauthorized, and unknown error responses. ```dart final projectsResp = await projectsClient.listProjects(); switch (projectsResp) { case r.ListProjectsResponseSuccess(:final data): _log('SUCCESS: ${data.length} projects'); for (final project in data) { _log(' - ${project.name} (owner: ${project.owner.name}, members: ${project.members.length})'); } case r.ListProjectsResponseUnauthorized(:final data): _log('UNAUTHORIZED: ${data.message}'); case r.ListProjectsResponseUnknown(:final statusCode, :final body): _log('UNKNOWN: status=$statusCode body=$body'); } ``` -------------------------------- ### Florval Configuration Reference Source: https://pub.dev/packages/florval A comprehensive reference for the florval.yaml configuration file, detailing options for schema path, output directory, client settings, and Riverpod integration. ```yaml florval: schema_path: openapi.yaml # Required. Path to OpenAPI spec. output_directory: lib/api/generated # Output directory. client: base_url_env: API_BASE_URL # Env var name for base URL. timeout: 30000 # Request timeout (ms). riverpod: enabled: false # Generate Riverpod providers. auto_invalidate: false # Invalidate GET providers after mutations. retry: # Riverpod-level retry for GET providers. max_attempts: 3 delay: 1000 # Initial delay (ms), linear backoff. pagination: # Cursor-based pagination endpoints. - operation_id: listItems cursor_param: after next_cursor_field: nextCursor items_field: items ``` -------------------------------- ### Build Generated Code Source: https://pub.dev/packages/florval Run the build_runner build command to process the generated code with tools like freezed and json_serializable. ```bash dart run build_runner build --delete-conflicting-outputs ``` -------------------------------- ### Demo Home Page State Management Source: https://pub.dev/packages/florval/example Manages the state for the demo home page, including a log buffer and a running status flag. Provides a helper method for logging messages to the UI. ```dart class DemoHomePage extends ConsumerStatefulWidget { final Dio dio; const DemoHomePage({super.key, required this.dio}); @override ConsumerState createState() => _DemoHomePageState(); } class _DemoHomePageState extends ConsumerState { final _logBuffer = []; bool _isRunning = false; void _log(String message) { setState(() { _logBuffer.add(message); }); } Future _runVerification() async { setState(() { _logBuffer.clear(); _isRunning = true; }); final authClient = ref.read(authApiClientProvider); final tasksClient = ref.read(tasksApiClientProvider); final usersClient = ref.read(usersApiClientProvider); final projectsClient = ref.read(projectsApiClientProvider); final notificationsClient = ref.read(notificationsApiClientProvider); // --- Test 1: Login --- _log('=== Test 1: POST /auth/login ==='); try { final loginResp = await authClient.login( body: LoginRequest(email: 'demo@example.com', password: 'password'), ); switch (loginResp) { case r.LoginResponseSuccess(:final data): final token = data.token; _log('SUCCESS: Logged in as ${data.user.name}'); _log(' Token: ${token.substring(0, 20)}...'); // Set auth header on the shared Dio instance widget.dio.options.headers['Authorization'] = 'Bearer $token'; case r.LoginResponseUnauthorized(:final data): _log('UNAUTHORIZED: ${data.message}'); _log('Cannot continue without token'); setState(() => _isRunning = false); return; case r.LoginResponseUnknown(:final statusCode, :final body): _log('UNKNOWN: status=$statusCode body=$body'); setState(() => _isRunning = false); return; } } catch (e) { _log('ERROR: $e'); setState(() => _isRunning = false); return; } // --- Test 2: List Tasks --- _log(''); _log('=== Test 2: GET /tasks ==='); try { final tasksResp = await tasksClient.listTasks(); switch (tasksResp) { case r.ListTasksResponseSuccess(:final data): _log('SUCCESS: Found ${data.length} tasks'); if (data.isNotEmpty) { final first = data.first; _log(' First: "${first.title}" [${first.status}/${first.priority}]'); } case r.ListTasksResponseUnauthorized(:final data): _log('UNAUTHORIZED: ${data.message}'); case r.ListTasksResponseServerError(:final data): _log('SERVER ERROR: ${data.message}'); case r.ListTasksResponseUnknown(:final statusCode, :final body): _log('UNKNOWN: status=$statusCode body=$body'); } } catch (e) { _log('ERROR: $e'); } // --- Test 3: Create Task --- _log(''); _log('=== Test 3: POST /tasks ==='); String? createdTaskId; try { final createResp = await tasksClient.createTask( body: CreateTaskRequest( title: 'Florval verification task', description: 'Created by main.dart verification', tags: ['test', 'florval'], ), ); switch (createResp) { case r.CreateTaskResponseCreated(:final data): createdTaskId = data.id; ``` -------------------------------- ### Generate API Client Code Source: https://pub.dev/packages/florval Execute the florval generate command to create API client code based on your OpenAPI specification and florval.yaml configuration. ```bash dart run florval generate ``` -------------------------------- ### Flutter Widget for Demo API Verification Source: https://pub.dev/packages/florval/example This Flutter code defines a StatefulWidget that allows users to run a verification process against a local demo API. It displays logs and provides a button to initiate the process. Ensure the demo-api is running locally by navigating to its directory and running 'npm run dev'. ```dart } _log(''); _log('=== Verification Complete ==='); setState(() { _isRunning = false; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Florval Demo API Verification'), ), body: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Connects to demo-api at http://localhost:3000', style: Theme.of(context).textTheme.bodySmall, ), const SizedBox(height: 8), ElevatedButton( onPressed: _isRunning ? null : _runVerification, child: Text(_isRunning ? 'Running...' : 'Run Verification'), ), const SizedBox(height: 16), Expanded( child: Container( width: double.infinity, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey.shade900, borderRadius: BorderRadius.circular(8), ), child: SingleChildScrollView( child: SelectableText( _logBuffer.isEmpty ? 'Press "Run Verification" to start...\n\n' 'Make sure demo-api is running:\n' ' cd demo-api && npm run dev' : _logBuffer.join('\n'), style: const TextStyle( fontFamily: 'monospace', fontSize: 13, color: Colors.greenAccent, ), ), ), ), ), ], ), ), ); } } ``` ``` -------------------------------- ### List Users with Pagination Source: https://pub.dev/packages/florval/example Retrieves a paginated list of users, specifying the page number and limit. Handles success responses by logging user details and counts, and also handles unauthorized and unknown errors. ```dart final usersResp = await usersClient.listUsers(page: 1, limit: 5); switch (usersResp) { case r.ListUsersResponseSuccess(:final data): _log('SUCCESS: ${data.data.length} users (total: ${data.total}, pages: ${data.totalPages})'); for (final user in data.data) { _log(' - ${user.name} (${user.role})'); } case r.ListUsersResponseUnauthorized(:final data): _log('UNAUTHORIZED: ${data.message}'); case r.ListUsersResponseUnknown(:final statusCode, :final body): _log('UNKNOWN: status=$statusCode body=$body'); } ``` -------------------------------- ### MIT License Text Source: https://pub.dev/packages/florval/license This is the full text of the MIT License. It grants broad permissions for use, modification, and distribution, requiring only the inclusion of the copyright notice and license text. ```plaintext MIT License Copyright (c) 2025 florval contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` -------------------------------- ### Handle Create Task Response Source: https://pub.dev/packages/florval/example Processes different response types from a task creation API call, including success, unauthorized, validation errors, and unknown errors. ```dart case r.CreateTaskResponseSuccess(:final data) { _log('SUCCESS: Created task "${data.title}" (id: ${data.id})'); } case r.CreateTaskResponseUnauthorized(:final data) { _log('UNAUTHORIZED: ${data.message}'); } case r.CreateTaskResponseUnprocessableEntity(:final data) { _log('VALIDATION ERROR: ${data.message}'); } case r.CreateTaskResponseUnknown(:final statusCode, :final body) { _log('UNKNOWN: status=$statusCode body=$body'); } ``` -------------------------------- ### Florval Project Dependencies Source: https://pub.dev/packages/florval Declare these dependencies in your pubspec.yaml file to use Florval in your project. Conditional dependencies for Riverpod are noted. ```yaml dependencies: dio: ^5.0.0 freezed_annotation: ^3.0.0 json_annotation: ^4.0.0 # Only if riverpod.enabled: true riverpod: ^3.0.0 riverpod_annotation: ^3.0.0 dev_dependencies: build_runner: ^2.4.0 freezed: ^3.0.0 json_serializable: ^6.0.0 # Only if riverpod.enabled: true riverpod_generator: ^3.0.0 florval: ^0.2.0 ``` -------------------------------- ### Pattern Matching on API Response Source: https://pub.dev/packages/florval This Dart code demonstrates how to pattern-match on the response from the 'getTask' client method. It allows direct access to the 'Task' model on success or specific error data. ```dart final response = await client.getTask(id: taskId); switch (response) { case GetTaskResponseSuccess(:final data) => showTask(data), // data is Task case GetTaskResponseNotFound(:final data) => showError(data.message), case GetTaskResponseUnauthorized(:final data) => handleAuth(data), case GetTaskResponseUnknown(:final statusCode) => showError('Error: $statusCode'), } ``` -------------------------------- ### Add Florval to Flutter Project Source: https://pub.dev/packages/florval/install Use this command to add the florval package as a dependency in your Flutter project. ```bash $ flutter pub add florval ``` -------------------------------- ### Add Florval to Dart Project Source: https://pub.dev/packages/florval/install Use this command to add the florval package as a dependency in your Dart project. ```bash $ dart pub add florval ``` -------------------------------- ### List Notifications (Polymorphic) Source: https://pub.dev/packages/florval/example Retrieves a list of notifications, showcasing handling of polymorphic types using 'oneOf' and a discriminator. Logs the type and read status of the first few notifications. Handles success, unauthorized, and unknown errors. ```dart final notifResp = await notificationsClient.listNotifications(); switch (notifResp) { case r.ListNotificationsResponseSuccess(:final data): _log('SUCCESS: ${data.length} notifications'); for (final n in data.take(3)) { _log(' - [${n.type}] read=${n.isRead}'); } case r.ListNotificationsResponseUnauthorized(:final data): _log('UNAUTHORIZED: ${data.message}'); case r.ListNotificationsResponseUnknown(:final statusCode, :final body): _log('UNKNOWN: status=$statusCode body=$body'); } ``` -------------------------------- ### Write code to handle Discriminator Union Types Source: https://pub.dev/packages/florval When receiving a NotificationPayload, use a switch statement on the payload object to handle different union types. This ensures all possible cases are covered exhaustively and with type safety. ```dart final payload = NotificationPayload.fromJson(json); switch (payload) { case NotificationPayloadTaskAssigned(:final taskId, :final taskTitle): showAssignment(taskId, taskTitle); case NotificationPayloadCommentAdded(:final commentText): showComment(commentText); } ``` -------------------------------- ### Add Florval to Dev Dependencies Source: https://pub.dev/packages/florval Add florval to your project's dev_dependencies in pubspec.yaml. ```yaml dev_dependencies: florval: ^0.2.0 ``` -------------------------------- ### Freezed Model Generation with Inline Enums Source: https://pub.dev/packages/florval Generates a freezed Dart model from an OpenAPI schema, automatically converting inline enum properties into dedicated Dart enums with JSON serialization support. This ensures type safety and clean code. ```dart // models/task.dart @freezed abstract class Task with _$Task { const factory Task({ required String id, required String title, required String? description, required TaskStatus status, required TaskPriority priority, @JsonKey(name: 'assignee_id') required String? assigneeId, required User? assignee, required List tags, @JsonKey(name: 'due_date') required DateTime? dueDate, @JsonKey(name: 'created_at') required DateTime createdAt, @JsonKey(name: 'updated_at') required DateTime updatedAt, }) = _Task; factory Task.fromJson(Map json) => _$TaskFromJson(json); } ``` ```dart // models/task_status.dart — generated from inline enum enum TaskStatus { @JsonValue('todo') todo, @JsonValue('in_progress') inProgress, @JsonValue('done') done; String get jsonValue => switch (this) { TaskStatus.todo => 'todo', TaskStatus.inProgress => 'in_progress', TaskStatus.done => 'done', }; static TaskStatus fromJsonValue(String value) => values.firstWhere((e) => e.jsonValue == value); } ``` -------------------------------- ### Generate PUT request body with JsonOptional for partial updates Source: https://pub.dev/packages/florval Use JsonOptional to distinguish between a field not being sent and a field being explicitly set to null. This is useful for partial updates where you only want to send modified fields. ```dart // models/update_task_request.dart @Freezed(fromJson: false, toJson: false) abstract class UpdateTaskRequest with _$UpdateTaskRequest { const UpdateTaskRequest._(); const factory UpdateTaskRequest({ required String title, @Default(JsonOptional.absent()) JsonOptional description, required UpdateTaskRequestStatus status, required UpdateTaskRequestPriority priority, @JsonKey(name: 'assignee_id') @Default(JsonOptional.absent()) JsonOptional assigneeId, @JsonKey(name: 'due_date') @Default(JsonOptional.absent()) JsonOptional dueDate, @Default(JsonOptional>.absent()) JsonOptional> tags, }) = _UpdateTaskRequest; factory UpdateTaskRequest.fromJson(Map json) { /* ... */ } Map toJson() { /* ... */ } } ``` -------------------------------- ### Task Schema and Model Generation Source: https://pub.dev/packages/florval This section describes how Florval generates Dart models from OpenAPI schemas, including handling inline enums and converting them to Dart enums. ```APIDOC ### Schema Definition: Task This describes the structure of a Task object as defined in the OpenAPI specification. **Properties:** - **id** (string, format: uuid) - Required - Unique identifier for the task. - **title** (string) - Required - The title of the task. - **description** (string, nullable) - Optional - A detailed description of the task. - **status** (string, enum: [todo, in_progress, done]) - Required - The current status of the task. - **priority** (string, enum: [low, medium, high, urgent]) - Required - The priority level of the task. - **assignee_id** (string, nullable, format: uuid) - Optional - The ID of the user assigned to the task. - **tags** (array of strings) - Required - A list of tags associated with the task. - **due_date** (string, nullable, format: date-time) - Optional - The due date for the task. - **created_at** (string, format: date-time) - Required - The timestamp when the task was created. - **updated_at** (string, format: date-time) - Required - The timestamp when the task was last updated. **Generated Dart Model:** Florval generates a `freezed` Dart model (`Task`) from this schema. Inline enums for `status` and `priority` are automatically converted into dedicated Dart enums (`TaskStatus` and `TaskPriority`) with JSON serialization support. ``` -------------------------------- ### Delete Created Task Source: https://pub.dev/packages/florval/example Deletes a previously created task using its ID. Handles successful deletion (NoContent), and various error responses including unauthorized, not found, and unknown errors. ```dart if (createdTaskId != null) { _log(''); _log('=== Test 9: DELETE /tasks/$createdTaskId ==='); try { final deleteResp = await tasksClient.deleteTask(id: createdTaskId); switch (deleteResp) { case r.DeleteTaskResponseNoContent(): _log('SUCCESS: Deleted task $createdTaskId'); case r.DeleteTaskResponseUnauthorized(:final data): _log('UNAUTHORIZED: ${data.message}'); case r.DeleteTaskResponseNotFound(:final data): _log('NOT FOUND: ${data.message}'); case r.DeleteTaskResponseUnknown(:final statusCode, :final body): _log('UNKNOWN: status=$statusCode body=$body'); } } catch (e) { _log('ERROR: $e'); } } ``` -------------------------------- ### Handle API responses without exceptions or status code checks Source: https://pub.dev/packages/florval Florval's generated client ensures that every possible response status code is represented as a distinct, type-safe variant. This allows for exhaustive handling using switch statements, removing the need for manual error code checks or try-catch blocks for expected responses. ```dart // ❌ What other generators produce — you're on your own for error handling try { final user = await client.getUser(id: 42); // What if the server returned 404? 422? 500? // You don't know until it throws. } on DioException catch (e) { if (e.response?.statusCode == 404) { ... } else if (e.response?.statusCode == 422) { ... } // Manual, error-prone, no type safety } ``` -------------------------------- ### Trigger Server Error Source: https://pub.dev/packages/florval/example Calls an API endpoint designed to trigger a server error (5xx) and handles the expected server error response, along with success or other unexpected responses. ```dart final errorResp = await tasksClient.listTasks(triggerError: 'true'); switch (errorResp) { case r.ListTasksResponseServerError(:final data): _log('SERVER ERROR (expected): ${data.message} [${data.code}]'); case r.ListTasksResponseSuccess(:final data): _log('SUCCESS (unexpected): ${data.length} tasks'); default: _log('OTHER: $errorResp'); } ``` -------------------------------- ### Write PUT request body for partial updates Source: https://pub.dev/packages/florval When creating an UpdateTaskRequest, optional fields not provided will be omitted from the JSON payload. To explicitly clear an optional field, use JsonOptional.value(null). ```dart // Only update title — optional fields stay untouched on the server final body = UpdateTaskRequest( title: 'New title', status: UpdateTaskRequestStatus.done, priority: UpdateTaskRequestPriority.high, ); // → {"title": "New title", "status": "done", "priority": "high"} ``` ```dart // Explicitly clear the due date final body = UpdateTaskRequest( title: 'New title', status: UpdateTaskRequestStatus.done, priority: UpdateTaskRequestPriority.high, dueDate: JsonOptional.value(null), ); // → {"title": "New title", "status": "done", "priority": "high", "due_date": null} ``` -------------------------------- ### Generated Dio Client and Riverpod Provider Source: https://pub.dev/packages/florval florval generates a Dio client and Riverpod provider for the 'getTask' endpoint. Each status code is automatically routed to a typed variant for robust error handling. ```dart // clients/tasks_api_client.dart class TasksApiClient { final Dio _dio; TasksApiClient(this._dio); Future getTask({required String id}) async { try { final response = await _dio.get('/tasks/$id'); return switch (response.statusCode) { 200 => GetTaskResponse.success(Task.fromJson(response.data)), 401 => GetTaskResponse.unauthorized(UnauthorizedError.fromJson(response.data)), 404 => GetTaskResponse.notFound(NotFoundError.fromJson(response.data)), _ => GetTaskResponse.unknown(response.statusCode ?? 0, response.data), }; } on DioException catch (e) { /* same routing for error responses */ } } } // providers/tasks_providers.dart @Riverpod(retry: retry) class GetTask extends _$GetTask { @override FutureOr build({required String id}) async { final client = ref.watch(tasksApiClientProvider); return client.getTask(id: id); } } ``` -------------------------------- ### Generate Discriminator Union Types (oneOf/anyOf) with Freezed Source: https://pub.dev/packages/florval Florval generates Freezed sealed classes with unionKey and @FreezedUnionValue to represent OpenAPI oneOf/anyOf schemas. This provides type-safe handling of different payload types based on a discriminator property. ```dart @Freezed(unionKey: 'type') sealed class NotificationPayload with _$NotificationPayload { @FreezedUnionValue('task_assigned') const factory NotificationPayload.taskAssigned({ @JsonKey(name: 'task_id') required String taskId, @JsonKey(name: 'task_title') required String taskTitle, @JsonKey(name: 'assigned_by') required String assignedBy, }) = NotificationPayloadTaskAssigned; @FreezedUnionValue('comment_added') const factory NotificationPayload.commentAdded({ @JsonKey(name: 'task_id') required String taskId, @JsonKey(name: 'comment_text') required String commentText, @JsonKey(name: 'commented_by') required String commentedBy, }) = NotificationPayloadCommentAdded; factory NotificationPayload.fromJson(Map json) => _$NotificationPayloadFromJson(json); } ``` -------------------------------- ### Handle API responses with typed variants for each status code Source: https://pub.dev/packages/florval Florval generates distinct typed variants for each API response status code, eliminating the need for manual status code checks and providing compile-time safety. This approach avoids exceptions for expected error responses. ```dart // ✅ florval — every status code is a typed variant final response = await client.getTask(id: taskId); switch (response) { case GetTaskResponseSuccess(:final data) => showTask(data), case GetTaskResponseNotFound(:final data) => showError(data.message), case GetTaskResponseUnauthorized(:final data) => handleAuth(data), case GetTaskResponseUnknown(:final statusCode) => showError('Error: $statusCode'), } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.