Files

53 lines
1.9 KiB
Cheetah

---
description: "REST API conventions for {{PROJECT_NAME}}"
alwaysApply: true
---
# REST API Standards — {{PROJECT_NAME}}
## HTTP client setup (Dio)
```dart
// In core/network/dio_client.dart
Dio createDioClient({required AppConfig config}) {
final dio = Dio(BaseOptions(
baseUrl: config.baseUrl,
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 30),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
));
dio.interceptors.addAll([
AuthInterceptor(tokenStorage: getIt<TokenStorage>()),
LoggingInterceptor(), // debug builds only
RetryInterceptor(dio), // 3 retries on network errors
]);
return dio;
}
```
## DTOs (Data Transfer Objects)
- DTOs live in the `data/` layer — **never** pass raw JSON maps to the domain layer
- Use Freezed for DTOs if `codegen` includes `json_serializable` or `freezed`
- `fromJson` factory must handle null fields gracefully — API response fields are not guaranteed
## Error handling
```dart
// Map HTTP errors → AppError domain types
AppError _mapDioError(DioException e) => switch (e.type) {
DioExceptionType.connectionTimeout => const NetworkError(statusCode: null),
DioExceptionType.receiveTimeout => const NetworkError(statusCode: null),
DioExceptionType.badResponse => _mapStatusCode(e.response?.statusCode),
DioExceptionType.connectionError => const NetworkError(statusCode: null),
_ => UnknownError(e),
};
```
## API versioning
- Base URL includes version: `https://api.{{PROJECT_NAME}}.com/v1/`
- When upgrading API version, keep old version working until all clients migrate
## Auth token interceptor
- Inject `Authorization: Bearer <token>` automatically on every request
- On 401: refresh token once, retry original request, then logout if refresh fails
- On 403: map to `AppError.authError('Insufficient permissions')`