Feature/middlewares #9
| @ -0,0 +1,386 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | // ignore_for_file: public_member_api_docs, sort_constructors_first | ||||||
|  | import 'dart:convert'; | ||||||
|  | 
 | ||||||
|  | import 'package:wyatt_http_client/src/authentication/refresh_token_client.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/rest_client.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/utils/protocols.dart'; | ||||||
|  | 
 | ||||||
|  | enum EmailVerificationAction { | ||||||
|  |   signUp, | ||||||
|  |   resetPassword, | ||||||
|  |   changeEmail; | ||||||
|  | 
 | ||||||
|  |   String toSnakeCase() { | ||||||
|  |     return name.splitMapJoin( | ||||||
|  |       RegExp('[A-Z]'), | ||||||
|  |       onMatch: (m) => '_${m[0]?.toLowerCase()}', | ||||||
|  |       onNonMatch: (n) => n, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   factory EmailVerificationAction.fromString(String str) { | ||||||
|  |     return EmailVerificationAction.values.firstWhere( | ||||||
|  |       (EmailVerificationAction element) => element.toSnakeCase() == str, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class VerifyCode { | ||||||
|  |   final String email; | ||||||
|  |   final String verificationCode; | ||||||
|  |   final EmailVerificationAction action; | ||||||
|  |   VerifyCode({ | ||||||
|  |     required this.email, | ||||||
|  |     required this.verificationCode, | ||||||
|  |     required this.action, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   VerifyCode copyWith({ | ||||||
|  |     String? email, | ||||||
|  |     String? verificationCode, | ||||||
|  |     EmailVerificationAction? action, | ||||||
|  |   }) { | ||||||
|  |     return VerifyCode( | ||||||
|  |       email: email ?? this.email, | ||||||
|  |       verificationCode: verificationCode ?? this.verificationCode, | ||||||
|  |       action: action ?? this.action, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Map<String, dynamic> toMap() { | ||||||
|  |     return <String, dynamic>{ | ||||||
|  |       'email': email, | ||||||
|  |       'verification_code': verificationCode, | ||||||
|  |       'action': action.toSnakeCase(), | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   factory VerifyCode.fromMap(Map<String, dynamic> map) { | ||||||
|  |     return VerifyCode( | ||||||
|  |       email: map['email'] as String, | ||||||
|  |       verificationCode: map['verification_code'] as String, | ||||||
|  |       action: EmailVerificationAction.fromString(map['action'] as String), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   String toJson() => json.encode(toMap()); | ||||||
|  | 
 | ||||||
|  |   factory VerifyCode.fromJson(String source) => | ||||||
|  |       VerifyCode.fromMap(json.decode(source) as Map<String, dynamic>); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => | ||||||
|  |       'VerifyCode(email: $email, verificationCode: $verificationCode, action: $action)'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Account { | ||||||
|  |   final String email; | ||||||
|  |   final String? sessionId; | ||||||
|  |   Account({ | ||||||
|  |     required this.email, | ||||||
|  |     this.sessionId, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   Account copyWith({ | ||||||
|  |     String? email, | ||||||
|  |     String? sessionId, | ||||||
|  |   }) { | ||||||
|  |     return Account( | ||||||
|  |       email: email ?? this.email, | ||||||
|  |       sessionId: sessionId ?? this.sessionId, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Map<String, dynamic> toMap() { | ||||||
|  |     return <String, dynamic>{ | ||||||
|  |       'email': email, | ||||||
|  |       'session_id': sessionId, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   factory Account.fromMap(Map<String, dynamic> map) { | ||||||
|  |     return Account( | ||||||
|  |       email: map['email'] as String, | ||||||
|  |       sessionId: map['session_id'] != null ? map['session_id'] as String : null, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   String toJson() => json.encode(toMap()); | ||||||
|  | 
 | ||||||
|  |   factory Account.fromJson(String source) => | ||||||
|  |       Account.fromMap(json.decode(source) as Map<String, dynamic>); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => 'Account(email: $email, sessionId: $sessionId)'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class SignUp { | ||||||
|  |   final String sessionId; | ||||||
|  |   final String password; | ||||||
|  |   SignUp({ | ||||||
|  |     required this.sessionId, | ||||||
|  |     required this.password, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   SignUp copyWith({ | ||||||
|  |     String? sessionId, | ||||||
|  |     String? password, | ||||||
|  |   }) { | ||||||
|  |     return SignUp( | ||||||
|  |       sessionId: sessionId ?? this.sessionId, | ||||||
|  |       password: password ?? this.password, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Map<String, dynamic> toMap() { | ||||||
|  |     return <String, dynamic>{ | ||||||
|  |       'session_id': sessionId, | ||||||
|  |       'password': password, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   factory SignUp.fromMap(Map<String, dynamic> map) { | ||||||
|  |     return SignUp( | ||||||
|  |       sessionId: map['session_id'] as String, | ||||||
|  |       password: map['password'] as String, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   String toJson() => json.encode(toMap()); | ||||||
|  | 
 | ||||||
|  |   factory SignUp.fromJson(String source) => | ||||||
|  |       SignUp.fromMap(json.decode(source) as Map<String, dynamic>); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => 'SignUp(sessionId: $sessionId, password: $password)'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class TokenSuccess { | ||||||
|  |   final String accessToken; | ||||||
|  |   final String refreshToken; | ||||||
|  |   final Account account; | ||||||
|  |   TokenSuccess({ | ||||||
|  |     required this.accessToken, | ||||||
|  |     required this.refreshToken, | ||||||
|  |     required this.account, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   TokenSuccess copyWith({ | ||||||
|  |     String? accessToken, | ||||||
|  |     String? refreshToken, | ||||||
|  |     Account? account, | ||||||
|  |   }) { | ||||||
|  |     return TokenSuccess( | ||||||
|  |       accessToken: accessToken ?? this.accessToken, | ||||||
|  |       refreshToken: refreshToken ?? this.refreshToken, | ||||||
|  |       account: account ?? this.account, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Map<String, dynamic> toMap() { | ||||||
|  |     return <String, dynamic>{ | ||||||
|  |       'access_token': accessToken, | ||||||
|  |       'refresh_token': refreshToken, | ||||||
|  |       'account': account.toMap(), | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   factory TokenSuccess.fromMap(Map<String, dynamic> map) { | ||||||
|  |     return TokenSuccess( | ||||||
|  |       accessToken: map['access_token'] as String, | ||||||
|  |       refreshToken: map['refresh_token'] as String, | ||||||
|  |       account: Account.fromMap(map['account'] as Map<String, dynamic>), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   String toJson() => json.encode(toMap()); | ||||||
|  | 
 | ||||||
|  |   factory TokenSuccess.fromJson(String source) => | ||||||
|  |       TokenSuccess.fromMap(json.decode(source) as Map<String, dynamic>); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => | ||||||
|  |       'TokenSuccess(accessToken: $accessToken, refreshToken: $refreshToken, account: $account)'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Login { | ||||||
|  |   final String email; | ||||||
|  |   final String password; | ||||||
|  |   Login({ | ||||||
|  |     required this.email, | ||||||
|  |     required this.password, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   Login copyWith({ | ||||||
|  |     String? email, | ||||||
|  |     String? password, | ||||||
|  |   }) { | ||||||
|  |     return Login( | ||||||
|  |       email: email ?? this.email, | ||||||
|  |       password: password ?? this.password, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Map<String, dynamic> toMap() { | ||||||
|  |     return <String, dynamic>{ | ||||||
|  |       'email': email, | ||||||
|  |       'password': password, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   factory Login.fromMap(Map<String, dynamic> map) { | ||||||
|  |     return Login( | ||||||
|  |       email: map['email'] as String, | ||||||
|  |       password: map['password'] as String, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   String toJson() => json.encode(toMap()); | ||||||
|  | 
 | ||||||
|  |   factory Login.fromJson(String source) => | ||||||
|  |       Login.fromMap(json.decode(source) as Map<String, dynamic>); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() => 'Login(email: $email, password: $password)'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class FastAPI { | ||||||
|  |   final String baseUrl; | ||||||
|  |   final RefreshTokenClient client; | ||||||
|  |   final int apiVersion; | ||||||
|  | 
 | ||||||
|  |   FastAPI({ | ||||||
|  |     this.baseUrl = 'localhost:80', | ||||||
|  |     RefreshTokenClient? client, | ||||||
|  |     this.apiVersion = 1, | ||||||
|  |   }) : client = client ?? | ||||||
|  |             RefreshTokenClient( | ||||||
|  |               authorizationEndpoint: '', | ||||||
|  |               tokenEndpoint: '', | ||||||
|  |               accessTokenParser: (body) => body['access_token']! as String, | ||||||
|  |               refreshTokenParser: (body) => body['refresh_token']! as String, | ||||||
|  |               inner: RestClient( | ||||||
|  |                 protocol: Protocols.http, | ||||||
|  |                 authority: baseUrl, | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |   String get apiPath => '/api/v$apiVersion'; | ||||||
|  | 
 | ||||||
|  |   Future<void> sendSignUpCode(String email) async { | ||||||
|  |     final r = await client.post( | ||||||
|  |       Uri.parse('$apiPath/auth/send-sign-up-code'), | ||||||
|  |       body: <String, String>{ | ||||||
|  |         'email': email, | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |     if (r.statusCode != 201) { | ||||||
|  |       throw Exception('Invalid reponse: ${r.statusCode}'); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Future<Account> verifyCode(VerifyCode verifyCode) async { | ||||||
|  |     final r = await client.post( | ||||||
|  |       Uri.parse('$apiPath/auth/verify-code'), | ||||||
|  |       body: verifyCode.toMap(), | ||||||
|  |     ); | ||||||
|  |     if (r.statusCode != 202) { | ||||||
|  |       throw Exception('Invalid reponse: ${r.statusCode}'); | ||||||
|  |     } else { | ||||||
|  |       return Account.fromMap( | ||||||
|  |         (jsonDecode(r.body) as Map<String, dynamic>)['account'] | ||||||
|  |             as Map<String, dynamic>, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Future<Account> signUp(SignUp signUp) async { | ||||||
|  |     final r = await client.post( | ||||||
|  |       Uri.parse('$apiPath/auth/sign-up'), | ||||||
|  |       body: signUp.toMap(), | ||||||
|  |     ); | ||||||
|  |     if (r.statusCode != 201) { | ||||||
|  |       throw Exception('Invalid reponse: ${r.statusCode}'); | ||||||
|  |     } else { | ||||||
|  |       return Account.fromJson(r.body); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Future<TokenSuccess> signInWithPassword(Login login) async { | ||||||
|  |     final r = await client.authorize(login.toMap()); | ||||||
|  |     return TokenSuccess.fromJson(r.body); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Future<TokenSuccess> refresh() async { | ||||||
|  |     final r = await client.refresh(); | ||||||
|  |     return TokenSuccess.fromJson(r?.body ?? ''); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Future<List<Account>> getAccountList() async { | ||||||
|  |     final r = await client.get( | ||||||
|  |       Uri.parse('$apiPath/account'), | ||||||
|  |     ); | ||||||
|  |     if (r.statusCode != 200) { | ||||||
|  |       throw Exception('Invalid reponse: ${r.statusCode}'); | ||||||
|  |     } else { | ||||||
|  |       final list = (jsonDecode(r.body) as Map<String, dynamic>)['founds'] | ||||||
|  |           as List<Map<String, dynamic>>; | ||||||
|  |       final result = <Account>[]; | ||||||
|  |       for (final element in list) { | ||||||
|  |         result.add(Account.fromMap(element)); | ||||||
|  |       } | ||||||
|  |       return result; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void main(List<String> args) async { | ||||||
|  |   final api = FastAPI( | ||||||
|  |     client: RefreshTokenClient( | ||||||
|  |       authorizationEndpoint: '/api/v1/auth/sign-in-with-password', | ||||||
|  |       tokenEndpoint: '/api/v1/auth/refresh', | ||||||
|  |       accessTokenParser: (body) => body['access_token']! as String, | ||||||
|  |       refreshTokenParser: (body) => body['refresh_token']! as String, | ||||||
|  |       inner: RestClient( | ||||||
|  |         protocol: Protocols.http, | ||||||
|  |         authority: 'localhost:80', | ||||||
|  |       ), | ||||||
|  |     ), | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   // await api.sendSignUpCode('git@pcl.ovh'); | ||||||
|  |   // final verifiedAccount = await api.verifyCode( | ||||||
|  |   //   VerifyCode( | ||||||
|  |   //     email: 'git@pcl.ovh', | ||||||
|  |   //     verificationCode: '000000000', | ||||||
|  |   //     action: EmailVerificationAction.signUp, | ||||||
|  |   //   ), | ||||||
|  |   // ); | ||||||
|  |   // print(verifiedAccount); | ||||||
|  |   // final registeredAccount = await api.signUp( | ||||||
|  |   //   SignUp(sessionId: verifiedAccount.sessionId ?? '', password: 'password'), | ||||||
|  |   // ); | ||||||
|  |   // print(registeredAccount); | ||||||
|  |   final signedInAccount = await api.signInWithPassword( | ||||||
|  |     Login(email: 'git@pcl.ovh', password: 'password'), | ||||||
|  |   ); | ||||||
|  |   // print(signedInAccount); | ||||||
|  |   final accountList = await api.getAccountList(); | ||||||
|  |   print(accountList); | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								packages/wyatt_http_client/example/http_client_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								packages/wyatt_http_client/example/http_client_test.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Future<void> main(List<String> args) async { | ||||||
|  |   // final client = Oauth2Client( | ||||||
|  |   //   accessToken: 'test-token', | ||||||
|  |   //   inner: RestClient(protocol: Protocols.http, authority: 'localhost:80'), | ||||||
|  |   // ); | ||||||
|  |   // final client = RestClient( | ||||||
|  |   //   protocol: Protocols.http, | ||||||
|  |   //   authority: 'localhost:80', | ||||||
|  |   //   inner: Oauth2Client( | ||||||
|  |   //     authorizationEndpoint: '/api/v1/account/test', | ||||||
|  |   //     tokenEndpoint: '/api/v1/account/test', | ||||||
|  |   //     accessToken: 'test-token', | ||||||
|  |   //     refreshToken: 'refresh-token', | ||||||
|  |   //   ), | ||||||
|  |   // ); | ||||||
|  |   // final client = RestClient(protocol: Protocols.http, authority: 'localhost:80'); | ||||||
|  |   // final client =AwesomeRestClient(protocol: Protocols.http, authority: 'localhost:80'); | ||||||
|  |   // var r = await client.post( | ||||||
|  |   //   Uri.parse('/api/v1/account/test'), | ||||||
|  |   //   body: <String, String>{ | ||||||
|  |   //     'email': 'test@test.fr', | ||||||
|  |   //   }, | ||||||
|  |   // ); | ||||||
|  | } | ||||||
| @ -0,0 +1,87 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'dart:convert'; | ||||||
|  | import 'dart:typed_data'; | ||||||
|  | 
 | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/implemented_base_client.dart'; | ||||||
|  | 
 | ||||||
|  | abstract class AuthenticatedClient implements ImplementedBaseClient { | ||||||
|  |   final Client _inner; | ||||||
|  | 
 | ||||||
|  |   AuthenticatedClient({ | ||||||
|  |     Client? inner, | ||||||
|  |   }) : _inner = inner ?? Client(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void close() => _inner.close(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> head(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.head(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> get(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.get(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> post( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.post(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> put( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.put(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> patch( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.patch(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> delete( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.delete(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<String> read(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.read(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Uint8List> readBytes(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.readBytes(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<StreamedResponse> send(BaseRequest request) => _inner.send(request); | ||||||
|  | } | ||||||
| @ -14,8 +14,161 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
|  | import 'dart:convert'; | ||||||
|  | import 'dart:typed_data'; | ||||||
|  | 
 | ||||||
| import 'package:http/http.dart'; | import 'package:http/http.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/mixins/body_transformer.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/mixins/headers_transformer.dart'; | ||||||
| import 'package:wyatt_http_client/src/rest_client.dart'; | import 'package:wyatt_http_client/src/rest_client.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/utils/protocols.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/utils/utils.dart'; | ||||||
|  | 
 | ||||||
|  | class AwesomeClient extends BaseClient { | ||||||
|  |   final Client _inner; | ||||||
|  | 
 | ||||||
|  |   AwesomeClient({ | ||||||
|  |     Client? inner, | ||||||
|  |   }) : _inner = inner ?? Client(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<StreamedResponse> send(BaseRequest request) { | ||||||
|  |     return _inner.send(request); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class AwesomeRestClient extends AwesomeClient | ||||||
|  |     with HeadersTransformer, BodyTransformer { | ||||||
|  |   final Protocols protocol; | ||||||
|  |   final String? authority; | ||||||
|  | 
 | ||||||
|  |   AwesomeRestClient({ | ||||||
|  |     this.protocol = Protocols.https, | ||||||
|  |     this.authority = '', | ||||||
|  |     super.inner, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Object? bodyMutator(Object? body) { | ||||||
|  |     print('bodyMutator: Json encoding'); | ||||||
|  |     return jsonEncode(body); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Map<String, String>? headersMutator( | ||||||
|  |     Object? body, | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |   ) { | ||||||
|  |     print('headerMutator: Json encoding'); | ||||||
|  |     final mutation = { | ||||||
|  |       'content-type': 'application/json; charset=utf-8', | ||||||
|  |     }; | ||||||
|  |     if (headers != null) { | ||||||
|  |       headers.addAll(mutation); | ||||||
|  |       return headers; | ||||||
|  |     } else { | ||||||
|  |       return mutation; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   BaseRequest requestMutator(BaseRequest request) { | ||||||
|  |     print('requestMutator: scheme + authority'); | ||||||
|  |     final Uri uri = Uri.parse('${protocol.scheme}$authority${request.url}'); | ||||||
|  |     return Utils.copyRequestWith(request, url: uri); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class AwesomeUrlClient extends AuthenticatedClient { | ||||||
|  |   AwesomeUrlClient(super.inner); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class AwesomeOauth2Client extends AuthenticatedClient with HeadersTransformer { | ||||||
|  |   AwesomeOauth2Client(super.inner); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Map<String, String>? headersMutator( | ||||||
|  |     Object? body, | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |   ) { | ||||||
|  |     print('headersMutator: Token manager'); | ||||||
|  |     final mutation = { | ||||||
|  |       'authorization': 'Bearer TOKEN', | ||||||
|  |     }; | ||||||
|  |     if (headers != null) { | ||||||
|  |       headers.addAll(mutation); | ||||||
|  |       return headers; | ||||||
|  |     } else { | ||||||
|  |       return mutation; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | abstract class AuthenticatedClient implements Client { | ||||||
|  |   final Client _inner; | ||||||
|  | 
 | ||||||
|  |   Client get inner => _inner; | ||||||
|  | 
 | ||||||
|  |   AuthenticatedClient(BaseClient? inner) : _inner = inner ?? RestClient(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void close() => _inner.close(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> head(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.head(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> get(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.get(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> post( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.post(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> put( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.put(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> patch( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.patch(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> delete( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.delete(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<String> read(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.read(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Uint8List> readBytes(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.readBytes(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<StreamedResponse> send(BaseRequest request) => _inner.send(request); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| abstract class AuthenticationClient extends BaseClient { | abstract class AuthenticationClient extends BaseClient { | ||||||
|   final BaseClient _inner; |   final BaseClient _inner; | ||||||
| @ -24,6 +177,50 @@ abstract class AuthenticationClient extends BaseClient { | |||||||
| 
 | 
 | ||||||
|   AuthenticationClient(BaseClient? inner) : _inner = inner ?? RestClient(); |   AuthenticationClient(BaseClient? inner) : _inner = inner ?? RestClient(); | ||||||
| 
 | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> head(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.head(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> get(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.get(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> post( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.post(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> put( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.put(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> patch( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.patch(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> delete( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.delete(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   Future<StreamedResponse> send(BaseRequest request) { |   Future<StreamedResponse> send(BaseRequest request) { | ||||||
|     return _inner.send(request); |     return _inner.send(request); | ||||||
|  | |||||||
| @ -31,6 +31,7 @@ abstract class HeaderAuthenticationClient extends AuthenticationClient { | |||||||
|     final newHeader = modifyHeader(Map.from(request.headers), request); |     final newHeader = modifyHeader(Map.from(request.headers), request); | ||||||
|     request.headers.clear(); |     request.headers.clear(); | ||||||
|     request.headers.addAll(newHeader); |     request.headers.addAll(newHeader); | ||||||
|  |     print(newHeader); | ||||||
|     return super.send(request); |     return super.send(request); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
|  | import 'package:http/http.dart'; | ||||||
| import 'package:wyatt_http_client/src/authentication/interfaces/header_authentication_client.dart'; | import 'package:wyatt_http_client/src/authentication/interfaces/header_authentication_client.dart'; | ||||||
| 
 | 
 | ||||||
| typedef TokenParser = String Function(Map<String, dynamic>); | typedef TokenParser = String Function(Map<String, dynamic>); | ||||||
| @ -21,14 +22,14 @@ typedef TokenParser = String Function(Map<String, dynamic>); | |||||||
| abstract class Oauth2Client extends HeaderAuthenticationClient { | abstract class Oauth2Client extends HeaderAuthenticationClient { | ||||||
|   Oauth2Client(super.inner); |   Oauth2Client(super.inner); | ||||||
| 
 | 
 | ||||||
|   Future<void> refresh() { |   Future<Response?> refresh() { | ||||||
|     return Future.value(); |     return Future.value(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> authorize( |   Future<Response> authorize( | ||||||
|     Map<String, dynamic> body, { |     Map<String, dynamic> body, { | ||||||
|     Map<String, String>? headers, |     Map<String, String>? headers, | ||||||
|   }) { |   }) { | ||||||
|     return Future.value(); |     return Future<Response>.value(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,6 +23,78 @@ import 'package:wyatt_http_client/src/utils/header_keys.dart'; | |||||||
| import 'package:wyatt_http_client/src/utils/http_status.dart'; | import 'package:wyatt_http_client/src/utils/http_status.dart'; | ||||||
| import 'package:wyatt_http_client/src/utils/utils.dart'; | import 'package:wyatt_http_client/src/utils/utils.dart'; | ||||||
| 
 | 
 | ||||||
|  | // class Oauth2Client extends ImplementedBaseClient with RequestTransformer { | ||||||
|  | //   final String authorizationEndpoint; | ||||||
|  | //   final String tokenEndpoint; | ||||||
|  | //   String? accessToken; | ||||||
|  | //   String? refreshToken; | ||||||
|  | //   String? tokenToUse; | ||||||
|  | 
 | ||||||
|  | //   Oauth2Client({ | ||||||
|  | //     required this.authorizationEndpoint, | ||||||
|  | //     required this.tokenEndpoint, | ||||||
|  | //     this.accessToken, | ||||||
|  | //     this.refreshToken, | ||||||
|  | //     super.inner, | ||||||
|  | //   }) : tokenToUse = accessToken; | ||||||
|  | 
 | ||||||
|  | //   @override | ||||||
|  | //   BaseRequest requestMutator(BaseRequest request) { | ||||||
|  | //     print('Oauth2Client::requestMutator -> add authorization: $accessToken'); | ||||||
|  | //     final headers = request.headers; | ||||||
|  | //     final mutation = { | ||||||
|  | //       'Authorization': 'Bearer $tokenToUse', | ||||||
|  | //     }; | ||||||
|  | //     if (tokenToUse?.isNotEmpty ?? false) { | ||||||
|  | //       headers.addAll(mutation); | ||||||
|  | //       return Utils.copyRequestWith(request, headers: headers); | ||||||
|  | //     } | ||||||
|  | //     return request; | ||||||
|  | //   } | ||||||
|  | 
 | ||||||
|  | //   Future<Response?> refresh() async { | ||||||
|  | //     if (refreshToken?.isNotEmpty ?? false) { | ||||||
|  | //       tokenToUse = refreshToken; | ||||||
|  | 
 | ||||||
|  | //       final response = await get( | ||||||
|  | //         Uri.parse(tokenEndpoint), | ||||||
|  | //       ); | ||||||
|  | 
 | ||||||
|  | //       if (response.statusCode == HttpStatus.ok) { | ||||||
|  | //         // final body = json.decode(response.body) as Map<String, dynamic>; | ||||||
|  | //         // accessToken = accessTokenParser(body); | ||||||
|  | //         print('Oauth2Client::refresh -> ok'); | ||||||
|  | //       } | ||||||
|  | //       return response; | ||||||
|  | //     } | ||||||
|  | //     return null; | ||||||
|  | //   } | ||||||
|  | 
 | ||||||
|  | // @override | ||||||
|  | // Map<String, String>? headersMutator( | ||||||
|  | //   Object? body, | ||||||
|  | //   Map<String, String>? headers, | ||||||
|  | // ) { | ||||||
|  | //   print( | ||||||
|  | //     'Oauth2Client::headersMutator -> add authorization: $accessToken', | ||||||
|  | //   ); | ||||||
|  | //   final mutation = { | ||||||
|  | //     'Authorization': 'Bearer $accessToken', | ||||||
|  | //   }; | ||||||
|  | //   if (accessToken.isNotEmpty) { | ||||||
|  | //     if (headers != null) { | ||||||
|  | //       headers.addAll(mutation); | ||||||
|  | //       return headers; | ||||||
|  | //     } else { | ||||||
|  | //       return mutation; | ||||||
|  | //     } | ||||||
|  | //   } else { | ||||||
|  | //     return headers; | ||||||
|  | //   } | ||||||
|  | // } | ||||||
|  | 
 | ||||||
|  | // } | ||||||
|  | 
 | ||||||
| class RefreshTokenClient extends Oauth2Client { | class RefreshTokenClient extends Oauth2Client { | ||||||
|   final String authorizationEndpoint; |   final String authorizationEndpoint; | ||||||
|   final String tokenEndpoint; |   final String tokenEndpoint; | ||||||
| @ -50,6 +122,8 @@ class RefreshTokenClient extends Oauth2Client { | |||||||
|     Map<String, String> header, [ |     Map<String, String> header, [ | ||||||
|     BaseRequest? request, |     BaseRequest? request, | ||||||
|   ]) { |   ]) { | ||||||
|  |     print('accessToken $accessToken'); | ||||||
|  |     print('request $request'); | ||||||
|     if (accessToken != null && request != null) { |     if (accessToken != null && request != null) { | ||||||
|       header[authenticationHeader] = '$authenticationMethod $accessToken'; |       header[authenticationHeader] = '$authenticationMethod $accessToken'; | ||||||
|       return header; |       return header; | ||||||
| @ -58,13 +132,13 @@ class RefreshTokenClient extends Oauth2Client { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<void> authorize( |   Future<Response> authorize( | ||||||
|     Map<String, dynamic> body, { |     Map<String, dynamic> body, { | ||||||
|     Map<String, String>? headers, |     Map<String, String>? headers, | ||||||
|   }) async { |   }) async { | ||||||
|     final response = await inner.post( |     final response = await inner.post( | ||||||
|       Uri.parse(authorizationEndpoint), |       Uri.parse(authorizationEndpoint), | ||||||
|       body: jsonEncode(body), |       body: body, | ||||||
|       headers: headers, |       headers: headers, | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
| @ -80,10 +154,11 @@ class RefreshTokenClient extends Oauth2Client { | |||||||
|         this.refreshToken = refreshToken; |         this.refreshToken = refreshToken; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |     return response; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<void> refresh() async { |   Future<Response?> refresh() async { | ||||||
|     if (refreshToken != null) { |     if (refreshToken != null) { | ||||||
|       final Map<String, String> header = { |       final Map<String, String> header = { | ||||||
|         authenticationHeader: '$authenticationHeader $refreshToken', |         authenticationHeader: '$authenticationHeader $refreshToken', | ||||||
| @ -98,11 +173,16 @@ class RefreshTokenClient extends Oauth2Client { | |||||||
|         final body = json.decode(response.body) as Map<String, dynamic>; |         final body = json.decode(response.body) as Map<String, dynamic>; | ||||||
|         accessToken = accessTokenParser(body); |         accessToken = accessTokenParser(body); | ||||||
|       } |       } | ||||||
|  |       return response; | ||||||
|     } |     } | ||||||
|  |     return null; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<StreamedResponse> send(BaseRequest request) async { |   Future<StreamedResponse> send(BaseRequest request) async { | ||||||
|  |     final newHeader = modifyHeader(Map.from(request.headers), request); | ||||||
|  |     request.headers.clear(); | ||||||
|  |     request.headers.addAll(newHeader); | ||||||
|     final response = await super.send(request); |     final response = await super.send(request); | ||||||
| 
 | 
 | ||||||
|     if (response.statusCode == HttpStatus.unauthorized) { |     if (response.statusCode == HttpStatus.unauthorized) { | ||||||
|  | |||||||
| @ -0,0 +1,31 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | 
 | ||||||
|  | class ImplementedBaseClient extends BaseClient { | ||||||
|  |   final Client inner; | ||||||
|  | 
 | ||||||
|  |   ImplementedBaseClient({ | ||||||
|  |     Client? inner, | ||||||
|  |   }) : inner = inner ?? Client(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<StreamedResponse> send(BaseRequest request) { | ||||||
|  |     return inner.send(request); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										86
									
								
								packages/wyatt_http_client/lib/src/implemented_client.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								packages/wyatt_http_client/lib/src/implemented_client.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,86 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'dart:convert'; | ||||||
|  | import 'dart:typed_data'; | ||||||
|  | 
 | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | 
 | ||||||
|  | abstract class ImplementedClient extends BaseClient { | ||||||
|  |   final Client _inner; | ||||||
|  | 
 | ||||||
|  |   ImplementedClient({ | ||||||
|  |     Client? inner, | ||||||
|  |   }) : _inner = inner ?? Client(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void close() => _inner.close(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> head(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.head(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> get(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.get(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> post( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.post(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> put( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.put(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> patch( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.patch(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> delete( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) => | ||||||
|  |       _inner.delete(url, headers: headers, body: body, encoding: encoding); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<String> read(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.read(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Uint8List> readBytes(Uri url, {Map<String, String>? headers}) => | ||||||
|  |       _inner.readBytes(url, headers: headers); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<StreamedResponse> send(BaseRequest request) => _inner.send(request); | ||||||
|  | } | ||||||
| @ -0,0 +1,83 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'dart:convert'; | ||||||
|  | 
 | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | 
 | ||||||
|  | mixin BodyTransformer on Client { | ||||||
|  |   Object? bodyMutator(Object? body); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> post( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) { | ||||||
|  |     return super.post( | ||||||
|  |       url, | ||||||
|  |       headers: headers, | ||||||
|  |       body: bodyMutator(body), | ||||||
|  |       encoding: encoding, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> put( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) { | ||||||
|  |     return super.put( | ||||||
|  |       url, | ||||||
|  |       headers: headers, | ||||||
|  |       body: bodyMutator(body), | ||||||
|  |       encoding: encoding, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> patch( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) { | ||||||
|  |     return super.patch( | ||||||
|  |       url, | ||||||
|  |       headers: headers, | ||||||
|  |       body: bodyMutator(body), | ||||||
|  |       encoding: encoding, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> delete( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) { | ||||||
|  |     return super.delete( | ||||||
|  |       url, | ||||||
|  |       headers: headers, | ||||||
|  |       body: bodyMutator(body), | ||||||
|  |       encoding: encoding, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,131 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'dart:convert'; | ||||||
|  | import 'dart:typed_data'; | ||||||
|  | 
 | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | 
 | ||||||
|  | mixin HeadersTransformer on Client { | ||||||
|  |   Map<String, String>? headersMutator( | ||||||
|  |     Object? body, | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> head( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |   }) { | ||||||
|  |     return super.head( | ||||||
|  |       url, | ||||||
|  |       headers: headersMutator(null, headers), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> get( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |   }) { | ||||||
|  |     return super.get( | ||||||
|  |       url, | ||||||
|  |       headers: headersMutator(null, headers), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> post( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) { | ||||||
|  |     return super.post( | ||||||
|  |       url, | ||||||
|  |       headers: headersMutator(body, headers), | ||||||
|  |       body: body, | ||||||
|  |       encoding: encoding, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> put( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) { | ||||||
|  |     return super.put( | ||||||
|  |       url, | ||||||
|  |       headers: headersMutator(body, headers), | ||||||
|  |       body: body, | ||||||
|  |       encoding: encoding, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> patch( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) { | ||||||
|  |     return super.patch( | ||||||
|  |       url, | ||||||
|  |       headers: headersMutator(body, headers), | ||||||
|  |       body: body, | ||||||
|  |       encoding: encoding, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Response> delete( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |     Object? body, | ||||||
|  |     Encoding? encoding, | ||||||
|  |   }) { | ||||||
|  |     return super.delete( | ||||||
|  |       url, | ||||||
|  |       headers: headersMutator(body, headers), | ||||||
|  |       body: body, | ||||||
|  |       encoding: encoding, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<String> read( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |   }) { | ||||||
|  |     return super.read( | ||||||
|  |       url, | ||||||
|  |       headers: headersMutator(null, headers), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Uint8List> readBytes( | ||||||
|  |     Uri url, { | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |   }) { | ||||||
|  |     return super.readBytes( | ||||||
|  |       url, | ||||||
|  |       headers: headersMutator(null, headers), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,33 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | //  | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | //  | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | //  | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/implemented_base_client.dart'; | ||||||
|  | 
 | ||||||
|  | mixin Oauth2Transformer on ImplementedBaseClient { | ||||||
|  |   late final String authorizationEndpoint; | ||||||
|  |   late final String tokenEndpoint; | ||||||
|  |   String? accessToken; | ||||||
|  |   String? refreshToken; | ||||||
|  | 
 | ||||||
|  |   BaseRequest requestAuthenticator(BaseRequest request); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<StreamedResponse> send(BaseRequest request) { | ||||||
|  |     final req = requestAuthenticator(request); | ||||||
|  |     return super.send(req); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/implemented_base_client.dart'; | ||||||
|  | 
 | ||||||
|  | mixin RequestTransformer on ImplementedBaseClient { | ||||||
|  |   BaseRequest requestMutator(BaseRequest request); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<StreamedResponse> send(BaseRequest request) { | ||||||
|  |     return super.send(requestMutator(request)); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -14,25 +14,177 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
|  | import 'dart:convert'; | ||||||
|  | 
 | ||||||
| import 'package:http/http.dart'; | import 'package:http/http.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/implemented_base_client.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/mixins/body_transformer.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/mixins/headers_transformer.dart'; | ||||||
|  | import 'package:wyatt_http_client/src/mixins/request_transformer.dart'; | ||||||
| import 'package:wyatt_http_client/src/utils/protocols.dart'; | import 'package:wyatt_http_client/src/utils/protocols.dart'; | ||||||
| import 'package:wyatt_http_client/src/utils/utils.dart'; | import 'package:wyatt_http_client/src/utils/utils.dart'; | ||||||
| 
 | 
 | ||||||
| class RestClient extends BaseClient { | class RestClient extends ImplementedBaseClient | ||||||
|  |     with BodyTransformer, HeadersTransformer, RequestTransformer { | ||||||
|   final Protocols protocol; |   final Protocols protocol; | ||||||
|   final String? authority; |   final String? authority; | ||||||
| 
 | 
 | ||||||
|   final Client _inner; |  | ||||||
| 
 |  | ||||||
|   RestClient({ |   RestClient({ | ||||||
|     this.protocol = Protocols.https, |     this.protocol = Protocols.https, | ||||||
|     this.authority = '', |     this.authority = '', | ||||||
|     Client? inner, |     super.inner, | ||||||
|   }) : _inner = inner ?? Client(); |   }); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<StreamedResponse> send(BaseRequest request) { |   Object? bodyMutator(Object? body) { | ||||||
|  |     print( | ||||||
|  |       'RestClient::bodyMutator -> encode in json if body is Map: ${body is Map}', | ||||||
|  |     ); | ||||||
|  |     if (body is Map) { | ||||||
|  |       return jsonEncode(body); | ||||||
|  |     } | ||||||
|  |     return body; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Map<String, String>? headersMutator( | ||||||
|  |     Object? body, | ||||||
|  |     Map<String, String>? headers, | ||||||
|  |   ) { | ||||||
|  |     print( | ||||||
|  |       'RestClient::headersMutator -> add json content-type if body is Map: ${body is Map}', | ||||||
|  |     ); | ||||||
|  |     final mutation = { | ||||||
|  |       'content-type': 'application/json; charset=utf-8', | ||||||
|  |     }; | ||||||
|  |     if (body is Map) { | ||||||
|  |       if (headers != null) { | ||||||
|  |         headers.addAll(mutation); | ||||||
|  |         return headers; | ||||||
|  |       } else { | ||||||
|  |         return mutation; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return headers; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   BaseRequest requestMutator(BaseRequest request) { | ||||||
|  |     print( | ||||||
|  |       'RestClient::requestMutator -> add prefix path: ${protocol.scheme}$authority', | ||||||
|  |     ); | ||||||
|     final Uri uri = Uri.parse('${protocol.scheme}$authority${request.url}'); |     final Uri uri = Uri.parse('${protocol.scheme}$authority${request.url}'); | ||||||
|     return _inner.send(Utils.copyRequestWith(request, url: uri)); |     return Utils.copyRequestWith(request, url: uri); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // class RestClient extends BaseClient { | ||||||
|  | //   final Protocols protocol; | ||||||
|  | //   final String? authority; | ||||||
|  | 
 | ||||||
|  | //   final Client _inner; | ||||||
|  | 
 | ||||||
|  | //   RestClient({ | ||||||
|  | //     this.protocol = Protocols.https, | ||||||
|  | //     this.authority = '', | ||||||
|  | //     Client? inner, | ||||||
|  | //   }) : _inner = inner ?? Client(); | ||||||
|  | 
 | ||||||
|  | //   String? forceJson(Object? body) { | ||||||
|  | //     String? b; | ||||||
|  | //     if (body != null && body is Map) { | ||||||
|  | //       b = jsonEncode(body); | ||||||
|  | //     } | ||||||
|  | //     return b; | ||||||
|  | //   } | ||||||
|  | 
 | ||||||
|  | //   Map<String, String>? forceJsonHeader( | ||||||
|  | //       Object? body, Map<String, String>? headers,) { | ||||||
|  | //     final Map<String, String> h = headers ?? {}; | ||||||
|  | //     if (body != null && body is Map) { | ||||||
|  | //       h['Content-Type'] = 'application/json'; | ||||||
|  | //     } | ||||||
|  | //     return h; | ||||||
|  | //   } | ||||||
|  | 
 | ||||||
|  | //   // @override | ||||||
|  | //   // Future<Response> post( | ||||||
|  | //   //   Uri url, { | ||||||
|  | //   //   Map<String, String>? headers, | ||||||
|  | //   //   Object? body, | ||||||
|  | //   //   Encoding? encoding, | ||||||
|  | //   // }) { | ||||||
|  | //   //   final b = forceJson(body) ?? body; | ||||||
|  | //   //   final h = forceJsonHeader(body, headers) ?? headers; | ||||||
|  | //   //   print(b); | ||||||
|  | //   //   print(h); | ||||||
|  | //   //   return super.post( | ||||||
|  | //   //     url, | ||||||
|  | //   //     headers: h, | ||||||
|  | //   //     body: b, | ||||||
|  | //   //     encoding: encoding, | ||||||
|  | //   //   ); | ||||||
|  | //   // } | ||||||
|  | 
 | ||||||
|  | //   @override | ||||||
|  | //   Future<Response> put( | ||||||
|  | //     Uri url, { | ||||||
|  | //     Map<String, String>? headers, | ||||||
|  | //     Object? body, | ||||||
|  | //     Encoding? encoding, | ||||||
|  | //   }) { | ||||||
|  | //     final b = forceJson(body) ?? body; | ||||||
|  | //     final h = forceJsonHeader(body, headers) ?? headers; | ||||||
|  | //     return super.put( | ||||||
|  | //       url, | ||||||
|  | //       headers: h, | ||||||
|  | //       body: b, | ||||||
|  | //       encoding: encoding, | ||||||
|  | //     ); | ||||||
|  | //   } | ||||||
|  | 
 | ||||||
|  | //   @override | ||||||
|  | //   Future<Response> patch( | ||||||
|  | //     Uri url, { | ||||||
|  | //     Map<String, String>? headers, | ||||||
|  | //     Object? body, | ||||||
|  | //     Encoding? encoding, | ||||||
|  | //   }) { | ||||||
|  | //     final b = forceJson(body) ?? body; | ||||||
|  | //     final h = forceJsonHeader(body, headers) ?? headers; | ||||||
|  | //     return super.patch( | ||||||
|  | //       url, | ||||||
|  | //       headers: h, | ||||||
|  | //       body: b, | ||||||
|  | //       encoding: encoding, | ||||||
|  | //     ); | ||||||
|  | //   } | ||||||
|  | 
 | ||||||
|  | //   @override | ||||||
|  | //   Future<Response> delete( | ||||||
|  | //     Uri url, { | ||||||
|  | //     Map<String, String>? headers, | ||||||
|  | //     Object? body, | ||||||
|  | //     Encoding? encoding, | ||||||
|  | //   }) { | ||||||
|  | //     final b = forceJson(body) ?? body; | ||||||
|  | //     final h = forceJsonHeader(body, headers) ?? headers; | ||||||
|  | //     return super.delete( | ||||||
|  | //       url, | ||||||
|  | //       headers: h, | ||||||
|  | //       body: b, | ||||||
|  | //       encoding: encoding, | ||||||
|  | //     ); | ||||||
|  | //   } | ||||||
|  | 
 | ||||||
|  | //   @override | ||||||
|  | //   Future<StreamedResponse> send(BaseRequest request) { | ||||||
|  | //     final Uri uri = Uri.parse('${protocol.scheme}$authority${request.url}'); | ||||||
|  | //     return _inner.send( | ||||||
|  | //       Utils.copyRequestWith( | ||||||
|  | //         request, | ||||||
|  | //         url: uri, | ||||||
|  | //       ), | ||||||
|  | //     ); | ||||||
|  | //   } | ||||||
|  | // } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user