Adapt app client to JSON API payloads
This commit is contained in:
@@ -3,7 +3,9 @@ import 'package:dio/dio.dart';
|
|||||||
/// HTTP-клиент для одного сервера Ignis.
|
/// HTTP-клиент для одного сервера Ignis.
|
||||||
/// Покрывает все эндпоинты из openapi.json.
|
/// Покрывает все эндпоинты из openapi.json.
|
||||||
class IgnisApi {
|
class IgnisApi {
|
||||||
final Dio _dio = Dio();
|
IgnisApi({Dio? dio}) : _dio = dio ?? Dio();
|
||||||
|
|
||||||
|
final Dio _dio;
|
||||||
Dio get dioInstance => _dio;
|
Dio get dioInstance => _dio;
|
||||||
|
|
||||||
static String normalizeBaseUrl(String baseUrl) {
|
static String normalizeBaseUrl(String baseUrl) {
|
||||||
@@ -70,11 +72,11 @@ class IgnisApi {
|
|||||||
|
|
||||||
/// Управление группой: state, brightness, temp, scene, r/g/b
|
/// Управление группой: state, brightness, temp, scene, r/g/b
|
||||||
Future<Response> controlGroup(String id, Map<String, dynamic> params) =>
|
Future<Response> controlGroup(String id, Map<String, dynamic> params) =>
|
||||||
_dio.post('/control/group/$id', queryParameters: params);
|
_dio.post('/control/group/$id', data: params);
|
||||||
|
|
||||||
/// Управление одной лампой
|
/// Управление одной лампой
|
||||||
Future<Response> controlDevice(String id, Map<String, dynamic> params) =>
|
Future<Response> controlDevice(String id, Map<String, dynamic> params) =>
|
||||||
_dio.post('/control/device/$id', queryParameters: params);
|
_dio.post('/control/device/$id', data: params);
|
||||||
|
|
||||||
/// Мигнуть лампой (для идентификации)
|
/// Мигнуть лампой (для идентификации)
|
||||||
Future<Response> blinkDevice(String id) =>
|
Future<Response> blinkDevice(String id) =>
|
||||||
@@ -92,11 +94,11 @@ class IgnisApi {
|
|||||||
|
|
||||||
/// Одноразовое расписание (таймер)
|
/// Одноразовое расписание (таймер)
|
||||||
Future<Response> scheduleOnce(Map<String, dynamic> params) =>
|
Future<Response> scheduleOnce(Map<String, dynamic> params) =>
|
||||||
_dio.post('/schedules/once', queryParameters: params);
|
_dio.post('/schedules/once', data: params);
|
||||||
|
|
||||||
/// Cron-расписание (повторяющееся)
|
/// Cron-расписание (повторяющееся)
|
||||||
Future<Response> scheduleCron(Map<String, dynamic> params) =>
|
Future<Response> scheduleCron(Map<String, dynamic> params) =>
|
||||||
_dio.post('/schedules/cron', queryParameters: params);
|
_dio.post('/schedules/cron', data: params);
|
||||||
|
|
||||||
/// Все активные задачи расписания
|
/// Все активные задачи расписания
|
||||||
Future<Response> getTasks() => _dio.get('/schedules/tasks');
|
Future<Response> getTasks() => _dio.get('/schedules/tasks');
|
||||||
|
|||||||
86
test/api_client_test.dart
Normal file
86
test/api_client_test.dart
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:ignis_app/services/api_client.dart';
|
||||||
|
|
||||||
|
class RecordingAdapter implements HttpClientAdapter {
|
||||||
|
RequestOptions? lastRequest;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ResponseBody> fetch(
|
||||||
|
RequestOptions options,
|
||||||
|
Stream<Uint8List>? requestStream,
|
||||||
|
Future<void>? cancelFuture,
|
||||||
|
) async {
|
||||||
|
lastRequest = options;
|
||||||
|
return ResponseBody.fromString(
|
||||||
|
'{}',
|
||||||
|
200,
|
||||||
|
headers: {
|
||||||
|
Headers.contentTypeHeader: ['application/json'],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void close({bool force = false}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
test('controlGroup sends command payload in request body', () async {
|
||||||
|
final adapter = RecordingAdapter();
|
||||||
|
final dio = Dio()..httpClientAdapter = adapter;
|
||||||
|
final api = IgnisApi(dio: dio)..init('http://localhost:8000', 'secret');
|
||||||
|
|
||||||
|
await api.controlGroup('kitchen', {'state': true, 'brightness': 42});
|
||||||
|
|
||||||
|
expect(adapter.lastRequest, isNotNull);
|
||||||
|
expect(adapter.lastRequest?.path, '/control/group/kitchen');
|
||||||
|
expect(adapter.lastRequest?.queryParameters, isEmpty);
|
||||||
|
expect(adapter.lastRequest?.data, {'state': true, 'brightness': 42});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('scheduleOnce sends schedule payload in request body', () async {
|
||||||
|
final adapter = RecordingAdapter();
|
||||||
|
final dio = Dio()..httpClientAdapter = adapter;
|
||||||
|
final api = IgnisApi(dio: dio)..init('http://localhost:8000', 'secret');
|
||||||
|
|
||||||
|
await api.scheduleOnce({
|
||||||
|
'target_id': 'hall',
|
||||||
|
'hours_from_now': 4,
|
||||||
|
'state': false,
|
||||||
|
'is_group': true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(adapter.lastRequest, isNotNull);
|
||||||
|
expect(adapter.lastRequest?.path, '/schedules/once');
|
||||||
|
expect(adapter.lastRequest?.queryParameters, isEmpty);
|
||||||
|
expect(adapter.lastRequest?.data, {
|
||||||
|
'target_id': 'hall',
|
||||||
|
'hours_from_now': 4,
|
||||||
|
'state': false,
|
||||||
|
'is_group': true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'createApiKey keeps query-based contract until backend is changed',
|
||||||
|
() async {
|
||||||
|
final adapter = RecordingAdapter();
|
||||||
|
final dio = Dio()..httpClientAdapter = adapter;
|
||||||
|
final api = IgnisApi(dio: dio)..init('http://localhost:8000', 'secret');
|
||||||
|
|
||||||
|
await api.createApiKey('Guest', isAdmin: true);
|
||||||
|
|
||||||
|
expect(adapter.lastRequest, isNotNull);
|
||||||
|
expect(adapter.lastRequest?.path, '/api-keys');
|
||||||
|
expect(adapter.lastRequest?.queryParameters, {
|
||||||
|
'name': 'Guest',
|
||||||
|
'is_admin': true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user