iws_http_model 1.0.0
iws_http_model: ^1.0.0 copied to clipboard
Library for HTTP requests with the common operations CRUD, pagination and error handling.
Library for HTTP requests with the common CRUD operations, pagination and error handling.
Features #
- Authentication: JWT token and API key support.
- HTTP Error Handling: Built-in error handling for HTTP requests.
- REST Route Builder: Helper methods for building REST API endpoints.
- Complete CRUD Operations:
- Get by ID (GET) - Retrieve single records with optional path parameters
- Paginated Query (GET) - Fetch paginated lists with query parameters
- Paginated Search (POST) - Advanced search with request body and ordering
- Create (POST) - Add new records
- Update (PUT) - Complete record updates
- Partial Update (PATCH) - Partial record updates
- Delete (DELETE) - Remove records
- Flexible Path Management:
- Custom path support with parameter substitution
- Dynamic URL generation
- Support for nested resource paths
- Advanced Pagination:
- Built-in pagination metadata handling
- Configurable page sizes and ordering
- Support for both GET and POST pagination
- Type Safety: Full generic type support for model serialization
Getting started #
Initialize the IwsHttp library:
IwsHttp.setup(
authority: 'mydomain.com',
apiKey: 'my_secret_api_key',
basePath: 'api/',
secureConnection: true,
bearerToken: 'my_secret_token');
Usage #
Instantiate IwsHttpModel #
final myModelProvider = IwsHttpModel<MyModelClass>(
path: 'myModels',
iwsHttp: IwsHttp(),
fromJson: MyModelClass.fromJson,
toJson: MyModelClass.toJson,
resultAttribute: 'data' // Optional, defaults to 'data'
);
Available Methods #
1. Get by ID
Retrieve a single model by its identifier.
// Basic usage
MyModelClass myModel = await myModelProvider.get(120);
// With custom path and parameters
MyModelClass myModel = await myModelProvider.get(
120,
customPath: 'users/{userId}/models',
pathParams: {'userId': 456},
queryParameters: {'include': 'relations'},
auth: true,
apiKey: true
);
2. Paginated Query (GET)
Retrieve a paginated list of models using GET request.
// Basic usage
PaginatedData<MyModelClass> result = await myModelProvider.fetchPaginated();
// With pagination and query parameters
PaginatedData<MyModelClass> result = await myModelProvider.fetchPaginated(
page: 2,
queryParameters: {
'filter': 'active',
'orderBy': 'name',
'orderType': 'asc'
},
customPath: 'users/{userId}/models',
pathParams: {'userId': 456},
auth: true,
apiKey: true
);
3. Paginated Search (POST)
Retrieve a paginated list of models using POST request with search criteria.
// Basic usage with search body
PaginatedData<MyModelClass> result = await myModelProvider.fetchPaginatedQuery(
body: {
'search': 'search term',
'filters': {'status': 'active'}
}
);
// Advanced usage with all parameters
PaginatedData<MyModelClass> result = await myModelProvider.fetchPaginatedQuery(
page: 1,
orderBy: 'created_at',
orderType: OrderType.desc,
queryParameters: {'include': 'relations'},
customPath: 'search/models',
pathParams: {'category': 'electronics'},
body: {
'search': 'iPhone',
'filters': {
'price_min': 100,
'price_max': 1000
}
},
auth: true,
apiKey: true
);
4. Create (POST)
Add a new model.
// Basic usage
MyModelClass newModel = MyModelClass(name: 'New Item');
MyModelClass createdModel = await myModelProvider.add(newModel);
// With custom path and parameters
MyModelClass createdModel = await myModelProvider.add(
newModel,
customPath: 'users/{userId}/models',
pathParams: {'userId': 456}
);
5. Update (PUT)
Update an existing model completely.
// Basic usage
MyModelClass updatedModel = MyModelClass(id: 120, name: 'Updated Item');
MyModelClass result = await myModelProvider.update(updatedModel, 120);
// With custom path and parameters
MyModelClass result = await myModelProvider.update(
updatedModel,
120,
customPath: 'users/{userId}/models',
pathParams: {'userId': 456}
);
6. Partial Update (PATCH)
Update an existing model partially.
// Basic usage
MyModelClass partialModel = MyModelClass(name: 'Only name updated');
MyModelClass result = await myModelProvider.patchUpdate(partialModel, 120);
// With custom path and parameters
MyModelClass result = await myModelProvider.patchUpdate(
partialModel,
120,
customPath: 'users/{userId}/models',
pathParams: {'userId': 456}
);
7. Delete
Delete a model by ID.
// Basic usage
await myModelProvider.delete(120);
// With custom path and parameters
await myModelProvider.delete(
120,
customPath: 'users/{userId}/models',
pathParams: {'userId': 456}
);
8. Generate URL
Generate the endpoint URL for debugging or custom requests.
// Basic URL generation
String url = myModelProvider.generateURL();
// With custom path, parameters and ID
String url = myModelProvider.generateURL(
customPath: 'users/{userId}/models/{modelId}',
pathParam: {'userId': 456, 'modelId': 120},
id: '120'
);
Working with Paginated Data #
The fetchPaginated and fetchPaginatedQuery methods return a PaginatedData<T> object:
PaginatedData<MyModelClass> result = await myModelProvider.fetchPaginated();
// Access the data
List<MyModelClass> models = result.data;
// Access pagination metadata
ListMetaData meta = result.meta;
int currentPage = meta.currentPage;
int totalPages = meta.lastPage;
int? totalItems = meta.total;
int? itemsPerPage = meta.perPage;
int? fromItem = meta.from;
int? toItem = meta.to;
Order Types #
For search queries, you can specify the order type:
// Ascending order (default)
OrderType.asc
// Descending order
OrderType.desc
Path Parameters #
Use curly braces {} in custom paths to define parameters:
// Define path with parameters
customPath: 'users/{userId}/categories/{categoryId}/items'
// Replace parameters
pathParams: {
'userId': 123,
'categoryId': 'electronics'
}
// Results in: users/123/categories/electronics/items
Data Models #
PaginatedData
Contains paginated results and metadata:
class PaginatedData<T> {
List<T> data; // The actual data items
ListMetaData meta; // Pagination metadata
}
ListMetaData
Pagination information:
class ListMetaData {
int currentPage; // Current page number
int? from; // First item number on current page
int lastPage; // Total number of pages
int? perPage; // Items per page
int? to; // Last item number on current page
int? total; // Total number of items
}
OrderType Enum
Available ordering options:
enum OrderType {
asc, // Ascending order
desc // Descending order
}
JSON Structure for Pagination #
Paging queries expect a specific response format:
{
"data": [
{
"id": 1,
"name": "Item 1"
},
{
"id": 2,
"name": "Item 2"
}
],
"meta": {
"current_page": 1,
"from": 1,
"last_page": 2,
"per_page": 10,
"to": 10,
"total": 15
}
}
For non-paginated responses, you can return just the data array:
[
{
"id": 1,
"name": "Item 1"
}
]
Advanced Usage Examples #
Nested Resource Management
// Managing user payments
final paymentProvider = IwsHttpModel<Payment>(
path: 'users/{userId}/payments',
iwsHttp: IwsHttp(),
fromJson: Payment.fromJson,
toJson: Payment.toJson
);
// Get user's payments
PaginatedData<Payment> payments = await paymentProvider.fetchPaginated(
pathParams: {'userId': 123},
page: 1
);
// Create new payment for user
Payment newPayment = Payment(amount: 100.0, method: 'credit_card');
Payment created = await paymentProvider.add(
newPayment,
pathParams: {'userId': 123}
);
Custom Search with Complex Filters
// Advanced search with multiple filters
PaginatedData<Product> products = await productProvider.fetchPaginatedQuery(
page: 1,
orderBy: 'price',
orderType: OrderType.asc,
body: {
'search': 'smartphone',
'filters': {
'category': 'electronics',
'price_range': {
'min': 200,
'max': 1000
},
'brand': ['Apple', 'Samsung'],
'in_stock': true
},
'date_range': {
'from': '2024-01-01',
'to': '2024-12-31'
}
}
);
Error Handling
try {
MyModelClass model = await myModelProvider.get(999);
} on IwsHttpException catch (e) {
// Handle HTTP errors (404, 500, etc.)
print('HTTP Error: ${e.statusCode} - ${e.message}');
} catch (e) {
// Handle other errors
print('Error: $e');
}
Custom Result Attribute
If your API returns data in a different attribute:
final customProvider = IwsHttpModel<MyModel>(
path: 'models',
iwsHttp: IwsHttp(),
fromJson: MyModel.fromJson,
toJson: MyModel.toJson,
resultAttribute: 'result' // API returns {"result": {...}}
);
Best Practices #
- Reuse IwsHttpModel instances: Create them once and reuse throughout your app
- Use path parameters: For dynamic routes, prefer path parameters over custom paths
- Handle pagination: Always check
meta.lastPagewhen implementing infinite scroll - Error handling: Wrap HTTP calls in try-catch blocks
- Type safety: Define proper model classes with
fromJsonandtoJsonmethods
Integration with State Management #
With Provider
class MyModelNotifier extends ChangeNotifier {
final IwsHttpModel<MyModel> _modelProvider;
List<MyModel> _models = [];
MyModelNotifier(this._modelProvider);
Future<void> loadModels() async {
try {
final result = await _modelProvider.fetchPaginated();
_models = result.data;
notifyListeners();
} catch (e) {
// Handle error
}
}
}
With BLoC
class MyModelBloc extends Bloc<MyModelEvent, MyModelState> {
final IwsHttpModel<MyModel> modelProvider;
MyModelBloc(this.modelProvider) : super(MyModelInitial()) {
on<LoadModels>(_onLoadModels);
}
Future<void> _onLoadModels(LoadModels event, Emitter<MyModelState> emit) async {
emit(MyModelLoading());
try {
final result = await modelProvider.fetchPaginated(page: event.page);
emit(MyModelLoaded(result.data, result.meta));
} catch (e) {
emit(MyModelError(e.toString()));
}
}
}
Request Parameters #
The parameters for paging and ordering are sent in the request route as follows:
https://exampledomain.com/api/models?page=1&orderBy=name&orderType=asc&filter=active
For POST requests with search body:
POST https://exampledomain.com/api/models/search?page=1&orderBy=created_at&orderType=desc
Content-Type: application/json
{
"search": "search term",
"filters": {
"status": "active",
"category": "electronics"
}
}