53 lines
1.9 KiB
Cheetah
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')`
|