Какие способы взаимодействия с серверным API ты используешь в Flutter?

Ответ

Для работы с API в Flutter я обычно выстраиваю клиент-серверное взаимодействие по следующей схеме, используя несколько ключевых пакетов.

1. HTTP-клиент: Dio или http.

  • dio — мой основной выбор для сложных проектов. Он предоставляет перехватчики (interceptors) для логирования, добавления заголовков, обработки ошибок, поддержку отмены запросов (CancelToken) и встроенный парсинг JSON.

    final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
    dio.interceptors.add(LogInterceptor()); // Логирование
    
    // Запрос с обработкой ошибок
    try {
      Response response = await dio.get('/users/1');
      User user = User.fromJson(response.data);
    } on DioException catch (e) {
      // Обработка ошибок сети/сервера
    }
  • http — более легковесный официальный пакет от команды Dart. Использую его для простых задач.

2. Сериализация данных: json_serializable + freezed или built_value. Автоматическая генерация кода для преобразования JSON в Dart-объекты и обратно. freezed — особенно удобен, так как создает неизменяемые (immutable) классы с методами copyWith.

    @freezed
    class User with _$User {
      factory User({
        required int id,
        required String name,
        String? email,
      }) = _User;
      factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
    }

3. Управление состоянием и кэширование. Запросы к API интегрируются в общую архитектуру управления состоянием (например, Bloc, Riverpod).

  • Кэширование ответов: Использую dio_http_cache или hive для локального хранения данных.
  • Повторные запросы при восстановлении связи: Пакет connectivity_plus в связке с логикой в Bloc/Cubit.

4. Альтернативные подходы к API:

  • GraphQL: Для проектов со сложными или часто меняющимися требованиями к данным использую пакет graphql_flutter.
  • WebSockets: Для real-time функций (чат, уведомления) — web_socket_channel.
  • gRPC: Для высокопроизводительной внутренней коммуникации в микросервисной архитектуре.

Типичная структура слоя данных:

lib/
  data/
    models/          # Классы моделей (User, Post) с json_serializable
    repositories/    # UserRepository (абстракция)
    datasources/     # UserRemoteDataSource (работа с Dio), UserLocalDataSource (Hive)
  domain/           # Бизнес-логика и use cases
  presentation/     # UI и состояние (Blocs/Providers)

Такой подход обеспечивает тестируемость, разделение ответственности и легкую замену источника данных (например, на мок для тестов).

Ответ 18+ 🔞

Слушай, я тут подумал, как обычно API в Flutter пилить, и понял, что у многих народ просто в ахуе с этого. Схема, в принципе, простая, но надо не распиздяйничать, а делать по уму, чтобы потом не орать «ёпта, что сломалось?».

1. HTTP-клиент: Dio или http.

  • dio — это, блядь, просто царь и бог для сложных проектов. Он тебе и перехватчики (interceptors) для всякой хуйни вроде логирования или заголовков подкинет, и запрос отменить поможет, и JSON сам распарсит. Просто овердохуища удобства.

    final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
    dio.interceptors.add(LogInterceptor()); // Чтобы видеть, что куда летит
    
    // Ну и запрос, понятное дело
    try {
      Response response = await dio.get('/users/1');
      User user = User.fromJson(response.data);
    } on DioException catch (e) {
      // А вот тут уже лови, если сервер накосячил или сеть легла
    }
  • http — это такой скромняга, официальный пакет. Легковесный, простой. Беру его, когда задача — раз плюнуть, и заморачиваться не хочется.

2. Сериализация данных: json_serializable + freezed или built_value. Это чтобы не писать эти ебучки Map<String, dynamic> руками, а то с ума сойти можно. freezed — вообще красава, делает неизменяемые классы, и метод copyWith сам генерит. Хуй моржовый, а не инструмент.

    @freezed
    class User with _$User {
      factory User({
        required int id,
        required String name,
        String? email,
      }) = _User;
      factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
    }

3. Управление состоянием и кэширование. Тут главное — не накосячить и не смешать всё в одну кучу. Запросы к API должны вписываться в твою архитектуру (Bloc, Riverpod — неважно).

  • Кэширование ответов: Чтобы каждый раз не дергать сервер, юзаю dio_http_cache или hive. Просто сохранил и забыл.
  • Повторные запросы: Это когда интернет пропал и появился. Берешь connectivity_plus, и в логике Bloc/Cubit делаешь перезапрос. Без этого — пидарас шерстяной, а не разработчик.

4. Альтернативные подходы к API:

  • GraphQL: Если у тебя требования к данным меняются чаще, чем трусы, то graphql_flutter — твой выбор. Иначе нихуя не успеешь.
  • WebSockets: Для реального времени — чаты, уведомления. Тут web_socket_channel рулит.
  • gRPC: Ну это уже для серьёзных ребят, где микросервисы и производительность на первом месте. Для пет-проекта — пиздопроебибна.

Типичная структура слоя данных:

lib/
  data/
    models/          # Модельки (User, Post) — тут json_serializable пашет
    repositories/    # UserRepository — абстракция, чтобы всё красиво было
    datasources/     # UserRemoteDataSource (работает с Dio), UserLocalDataSource (копошится в Hive)
  domain/           # Бизнес-логика, use cases
  presentation/     # UI и всё состояние (Blocs/Providers)

Вот такая хитрая жопа. Зато всё тестируемо, ответственность разделена, и если завтра скажут «делай на моках», ты просто один источник данных подменишь — и волнение ебать, всё работает.