wyatt-packages/packages/wyatt_http_client/example/http_client_fastapi_example.dart
Hugo Pointcheval 25cf9518f9
All checks were successful
continuous-integration/drone/push Build is passing
chore: fix all problems
2023-02-24 10:12:04 +01:00

372 lines
10 KiB
Dart

// 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/middleware_client.dart';
import 'package:wyatt_http_client/src/middlewares/body_to_json_middleware.dart';
import 'package:wyatt_http_client/src/middlewares/refresh_token_auth_middleware.dart';
import 'package:wyatt_http_client/src/middlewares/simple_logger_middleware.dart';
import 'package:wyatt_http_client/src/middlewares/uri_prefix_middleware.dart';
import 'package:wyatt_http_client/src/pipeline.dart';
import 'package:wyatt_http_client/src/utils/http_status.dart';
import 'package:wyatt_http_client/src/utils/protocols.dart';
enum EmailVerificationAction {
signUp,
resetPassword,
changeEmail;
String toSnakeCase() => name.splitMapJoin(
RegExp('[A-Z]'),
onMatch: (m) => '_${m[0]?.toLowerCase()}',
onNonMatch: (n) => n,
);
factory EmailVerificationAction.fromString(String str) =>
EmailVerificationAction.values.firstWhere(
(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,
}) =>
VerifyCode(
email: email ?? this.email,
verificationCode: verificationCode ?? this.verificationCode,
action: action ?? this.action,
);
Map<String, dynamic> toMap() => <String, dynamic>{
'email': email,
'verification_code': verificationCode,
'action': action.toSnakeCase(),
};
factory VerifyCode.fromMap(Map<String, dynamic> map) => 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,
}) =>
Account(
email: email ?? this.email,
sessionId: sessionId ?? this.sessionId,
);
Map<String, dynamic> toMap() => <String, dynamic>{
'email': email,
'session_id': sessionId,
};
factory Account.fromMap(Map<String, dynamic> map) => 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,
}) =>
SignUp(
sessionId: sessionId ?? this.sessionId,
password: password ?? this.password,
);
Map<String, dynamic> toMap() => <String, dynamic>{
'session_id': sessionId,
'password': password,
};
factory SignUp.fromMap(Map<String, dynamic> map) => 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,
}) =>
TokenSuccess(
accessToken: accessToken ?? this.accessToken,
refreshToken: refreshToken ?? this.refreshToken,
account: account ?? this.account,
);
Map<String, dynamic> toMap() => <String, dynamic>{
'access_token': accessToken,
'refresh_token': refreshToken,
'account': account.toMap(),
};
factory TokenSuccess.fromMap(Map<String, dynamic> map) => 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,
}) =>
Login(
email: email ?? this.email,
password: password ?? this.password,
);
Map<String, dynamic> toMap() => <String, dynamic>{
'email': email,
'password': password,
};
factory Login.fromMap(Map<String, dynamic> map) => 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 MiddlewareClient client;
final int apiVersion;
FastAPI({
this.baseUrl = 'localhost:80',
MiddlewareClient? client,
this.apiVersion = 1,
}) : client = client ?? MiddlewareClient();
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.post(
Uri.parse('$apiPath/auth/sign-in-with-password'),
body: login.toMap(),
);
if (r.statusCode != 200) {
throw Exception('Invalid reponse: ${r.statusCode}');
} else {
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 Pipeline pipeline = Pipeline()
.addMiddleware(
UriPrefixMiddleware(
protocol: Protocols.http,
authority: 'localhost:80',
),
)
.addMiddleware(BodyToJsonMiddleware())
.addMiddleware(
RefreshTokenAuthMiddleware(
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,
unauthorized: HttpStatus.forbidden,
),
)
.addMiddleware(SimpleLoggerMiddleware());
print(pipeline);
final client = MiddlewareClient(pipeline: pipeline);
final api = FastAPI(
client: client,
);
await api.sendSignUpCode('git@pcl.ovh');
// final verifiedAccount = await api.verifyCode(
// VerifyCode(
// email: 'git@pcl.ovh',
// verificationCode: '000000000',
// action: EmailVerificationAction.signUp,
// ),
// );
// final registeredAccount = await api.signUp(
// SignUp(sessionId: verifiedAccount.sessionId ?? '', password: 'password'),
// );
// final signedInAccount = await api.signInWithPassword(
// Login(email: 'git@pcl.ovh', password: 'password'),
// );
final accountList = await api.getAccountList();
print(accountList);
}