IwsHttp

Library to facilitate HTTP requests with REST APIs in Dart/Flutter. Provides JWT authentication, error handling, file upload, connection pooling/client injection, and convenient helpers for building API clients.

Features

  • Authentication with JWT (Bearer) and/or API Key
  • HTTP error handling with typed custom exceptions retaining full response payloads
  • File upload (multipart/form-data) supporting device paths, bytes, custom MIME types, and configurable field names
  • Support for GET, POST, PUT, PATCH, DELETE
  • Persistent HTTP client with connection pooling and custom http.Client injection (for tests with MockClient)
  • Automatic path normalization and dynamic path generation helper for RESTful endpoints
  • Session management utilities (updateBearerToken, clearSession)

Getting started

Initialize the library (singleton):

IwsHttp.setup(
  authority: 'api.mydomain.com',
  apiKey: 'my_secret_api_key',
  basePath: 'api/v1',
  secureConnection: true,
  bearerToken: 'my_secret_token',
  timeout: 10, // seconds
  defaultHeaders: {
    'Accept-Language': 'es-AR',
  },
);

Or create a new instance:

final client = IwsHttp.newInstance(
  authority: 'api.mydomain.com',
  apiKey: 'my_secret_api_key',
  basePath: 'api/v1',
  secureConnection: true,
  bearerToken: 'my_secret_token',
  timeout: 10,
);

Usage

Import the package:

import 'package:iws_http/iws_http.dart';

POST request

final response = await IwsHttp().post(
  path: 'login',
  body: {'email': 'user@example.com', 'password': '1234'},
  auth: false, // Set to false if endpoint does not require JWT
);

GET request

final data = await IwsHttp().get(
  path: 'users',
  queryParameters: {'page': '1'},
);

PUT request

await IwsHttp().put(
  path: 'users/1',
  body: {'name': 'New Name'},
);

PATCH request

await IwsHttp().patch(
  path: 'users/1',
  body: {'email': 'new@email.com'},
);

DELETE request

await IwsHttp().delete(
  path: 'users/1',
);

File upload (multipart/form-data)

// From device path
final file = FileDto(
  path: '/path/to/avatar.jpg',
  contentType: 'image/jpeg',
);

final result = await IwsHttp().upload(
  path: 'users/avatar',
  file: file,
  fieldName: 'avatar', // Custom field name (defaults to 'file')
  fields: {'userId': '123'},
);

// Or from in-memory bytes
final fileFromBytes = FileDto(
  bytes: uint8ListData,
  name: 'avatar.png',
  contentType: 'image/png',
);

Generate RESTful endpoint paths

final path = IwsHttp().generatePath(
  path: 'user/{userId}/payment/{paymentId}',
  pathParam: {'userId': 123, 'paymentId': 456},
);
// Result: 'user/123/payment/456'

Testing with MockClient

Inject a custom http.Client for fast, hermetic unit tests:

import 'package:http/testing.dart';
import 'package:http/http.dart' as http;
import 'package:iws_http/iws_http.dart';

final mockClient = MockClient((request) async {
  return http.Response('{"status": "ok"}', 200);
});

final client = IwsHttp.newInstance(
  authority: 'api.example.com',
  client: mockClient,
);

API Reference

Methods

IwsHttp.setup(...)

Initializes the singleton instance. Call this once at app startup. Supports optional client: http.Client and defaultAuth: bool.

IwsHttp.newInstance(...)

Creates a new, independent instance. Supports optional client: http.Client and defaultAuth: bool.

IwsHttp()

Returns the configured singleton instance.

post({required String path, body, ...})

Sends a POST request. body is encoded as JSON. Returns decoded response.

get({required String path, ...})

Sends a GET request. Returns decoded response.

put({required String path, body, ...})

Sends a PUT request. body is encoded as JSON.

patch({required String path, body, ...})

Sends a PATCH request. body is encoded as JSON.

delete({required String path, ...})

Sends a DELETE request. Optionally accepts a body.

upload({required String path, required FileDto file, String fieldName = 'file', int? timeout, ...})

Uploads a file using multipart/form-data. Accepts file path or bytes, optional MIME contentType, and custom field name.

generatePath({required String path, Map<String, dynamic>? pathParam, String? id})

Generates a RESTful endpoint path by URL-encoding and replacing {param} segments.

updateBearerToken(String? token)

Updates the bearer token for subsequent authenticated requests on this instance.

clearSession()

Clears authentication credentials (bearerToken and apiKey).

Error Handling

All methods throw custom exceptions extending ApiException for HTTP errors, retaining the status code and decoded response body:

  • ApiException (base, includes httpCode, error, and response)
  • BadRequestException (400)
  • UnauthorisedException (401/403)
  • DataNotFoundException (404)
  • FormRequestException (422, includes inputErrors and response)
  • FetchDataException (500, 429, connection errors)
try {
  final users = await IwsHttp().get(path: 'users');
} on FormRequestException catch (e) {
  print('Validation errors: ${e.inputErrors}');
} on UnauthorisedException catch (e) {
  print('Auth error: ${e.error}');
} on ApiException catch (e) {
  print('API error [${e.httpCode}]: ${e.error}, payload: ${e.response}');
}

Libraries

iws_http