monart_http 0.2.0
monart_http: ^0.2.0 copied to clipboard
HTTP client foundation for Dart built on monart. Create typed HTTP service objects using Railway-Oriented Programming with semantic outcomes per status code.
// Uses https://jsonplaceholder.typicode.com — a free public REST API for demos.
import 'package:monart/monart.dart';
import 'package:monart_http/monart_http.dart';
// ---------------------------------------------------------------------------
// Domain
// ---------------------------------------------------------------------------
class Post {
factory Post.fromJson(Map<String, dynamic> json) => Post(
id: json['id'] as int,
title: json['title'] as String,
content: json['body'] as String,
);
const Post({required this.id, required this.title, required this.content});
final int id;
final String title;
final String content;
@override
String toString() => 'Post(id: $id, title: "$title")';
}
// ---------------------------------------------------------------------------
// Configuration
// ---------------------------------------------------------------------------
const _config = HttpClientConfiguration(
baseUri: 'https://jsonplaceholder.typicode.com',
connectTimeout: Duration(seconds: 10),
receiveTimeout: Duration(seconds: 15),
logger: DevToolsHttpLogger(),
);
// ---------------------------------------------------------------------------
// Services
// ---------------------------------------------------------------------------
class PostFindService extends HttpServiceBase<Post> {
PostFindService({required this.postId});
final int postId;
@override
HttpMethod get method => HttpMethod.get;
@override
String get pathTemplate => '/posts/:postId';
@override
Map<String, String> get pathParams => {'postId': '$postId'};
@override
HttpClientConfiguration get configuration => _config;
@override
Post fromResponse(HttpResponse response) =>
Post.fromJson(response.body as Map<String, dynamic>);
}
class PostCreateService extends HttpServiceBase<Post> {
PostCreateService({required this.title, required this.content});
final String title;
final String content;
@override
HttpMethod get method => HttpMethod.post;
@override
String get pathTemplate => '/posts';
@override
HttpClientConfiguration get configuration => _config;
@override
Object? get body => {'title': title, 'body': content, 'userId': 1};
@override
Post fromResponse(HttpResponse response) =>
Post.fromJson(response.body as Map<String, dynamic>);
}
// ---------------------------------------------------------------------------
// Example
// ---------------------------------------------------------------------------
Future<void> main() async {
await _section('1. GET /posts/1 — fetch a post by id', () async {
await PostFindService(postId: 1)
.runAsync()
.onSuccessOf('ok', (Post post) => print(' Found: $post'))
.onFailureOf('notFound', (_) => print(' Post not found'))
.onFailure((String outcome, _) => print(' Failed: $outcome'));
});
await _section('2. GET /posts/9999 — not found', () async {
await PostFindService(postId: 9999)
.runAsync()
.onSuccessOf('ok', (Post post) => print(' Found: $post'))
.onFailureOf('notFound', (_) => print(' Post not found'))
.onFailure((String outcome, _) => print(' Failed: $outcome'));
});
await _section('3. POST /posts — create a post', () async {
await PostCreateService(title: 'Hello monart_http', content: 'Railway-Oriented HTTP calls.')
.runAsync()
.onSuccessOf('created', (Post post) => print(' Created: $post'))
.onFailure((String outcome, _) => print(' Failed: $outcome'));
});
await _section('4. Matching by family outcome', () async {
await PostFindService(postId: 1)
.runAsync()
.onSuccessOf('successful', (Post post) => print(' Success (any 2xx): $post'))
.onFailureOf('clientError', (_) => print(' Client error (any 4xx)'))
.onFailureOf('serverError', (_) => print(' Server error (any 5xx)'))
.onFailureOf('timeout', (_) => print(' Request timed out'))
.onFailure((String outcome, _) => print(' Other: $outcome'));
});
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
Future<void> _section(String title, Future<void> Function() block) async {
print('\n── $title');
await block();
}