refactor(frontend): adapt to RESTful API routes

This commit is contained in:
qzl
2026-02-26 14:28:58 +08:00
parent 5b8b584013
commit d635d9a5e0
16 changed files with 210 additions and 115 deletions
+24
View File
@@ -63,4 +63,28 @@ class ApiClient {
throw ApiException.fromDioError(e);
}
}
Future<Response<T>> patch<T>(
String path, {
dynamic data,
Options? options,
}) async {
try {
return await _dio.patch<T>(path, data: data, options: options);
} on DioException catch (e) {
throw ApiException.fromDioError(e);
}
}
Future<Response<T>> delete<T>(
String path, {
dynamic data,
Options? options,
}) async {
try {
return await _dio.delete<T>(path, data: data, options: options);
} on DioException catch (e) {
throw ApiException.fromDioError(e);
}
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ Future<void> configureDependencies() async {
apiClient.setRefreshCallback((token) async {
try {
await authRepository.refresh(token);
await authRepository.refreshSession(token);
return true;
} catch (_) {
return false;
+15 -17
View File
@@ -9,47 +9,45 @@ class AuthApi {
AuthApi(this._client);
Future<SignupStartResponse> signupStart(SignupStartRequest request) async {
Future<VerificationCreateResponse> createVerification(
SignupStartRequest request,
) async {
final response = await _client.post(
'$_prefix/signup/start',
'$_prefix/verifications',
data: request.toJson(),
);
return SignupStartResponse.fromJson(response.data);
return VerificationCreateResponse.fromJson(response.data);
}
Future<AuthResponse> signupVerify(SignupVerifyRequest request) async {
Future<AuthResponse> verifyVerification(SignupVerifyRequest request) async {
final response = await _client.post(
'$_prefix/signup/verify',
'$_prefix/verifications/verify',
data: request.toJson(),
);
return AuthResponse.fromJson(response.data);
}
Future<SignupResendResponse> signupResend(SignupResendRequest request) async {
final response = await _client.post(
'$_prefix/signup/resend',
data: request.toJson(),
);
return SignupResendResponse.fromJson(response.data);
Future<void> resendVerification(SignupResendRequest request) async {
await _client.post('$_prefix/verifications/resend', data: request.toJson());
}
Future<AuthResponse> login(LoginRequest request) async {
Future<AuthResponse> createSession(LoginRequest request) async {
final response = await _client.post(
'$_prefix/login',
'$_prefix/sessions',
data: request.toJson(),
);
return AuthResponse.fromJson(response.data);
}
Future<AuthResponse> refresh(RefreshRequest request) async {
Future<AuthResponse> refreshSession(RefreshRequest request) async {
final response = await _client.post(
'$_prefix/refresh',
'$_prefix/sessions/refresh',
data: request.toJson(),
);
return AuthResponse.fromJson(response.data);
}
Future<void> logout(LogoutRequest request) async {
await _client.post('$_prefix/logout', data: request.toJson());
Future<void> deleteSession(LogoutRequest request) async {
await _client.delete('$_prefix/sessions', data: request.toJson());
}
}
@@ -3,12 +3,14 @@ import 'package:social_app/features/auth/data/models/login_request.dart';
import 'package:social_app/features/auth/data/models/auth_response.dart';
abstract class AuthRepository {
Future<SignupStartResponse> signupStart(SignupStartRequest request);
Future<AuthResponse> signupVerify(SignupVerifyRequest request);
Future<SignupResendResponse> signupResend(SignupResendRequest request);
Future<AuthResponse> login(LoginRequest request);
Future<AuthResponse> refresh(String refreshToken);
Future<void> logout();
Future<VerificationCreateResponse> createVerification(
SignupStartRequest request,
);
Future<AuthResponse> verifyVerification(SignupVerifyRequest request);
Future<void> resendVerification(SignupResendRequest request);
Future<AuthResponse> createSession(LoginRequest request);
Future<AuthResponse> refreshSession(String refreshToken);
Future<void> deleteSession();
Future<String?> getAccessToken();
Future<String?> getRefreshToken();
Future<bool> isAuthenticated();
@@ -14,13 +14,15 @@ class AuthRepositoryImpl implements AuthRepository {
_tokenStorage = tokenStorage;
@override
Future<SignupStartResponse> signupStart(SignupStartRequest request) {
return _api.signupStart(request);
Future<VerificationCreateResponse> createVerification(
SignupStartRequest request,
) {
return _api.createVerification(request);
}
@override
Future<AuthResponse> signupVerify(SignupVerifyRequest request) async {
final response = await _api.signupVerify(request);
Future<AuthResponse> verifyVerification(SignupVerifyRequest request) async {
final response = await _api.verifyVerification(request);
await _tokenStorage.saveTokens(
access: response.accessToken,
refresh: response.refreshToken,
@@ -29,13 +31,13 @@ class AuthRepositoryImpl implements AuthRepository {
}
@override
Future<SignupResendResponse> signupResend(SignupResendRequest request) {
return _api.signupResend(request);
Future<void> resendVerification(SignupResendRequest request) {
return _api.resendVerification(request);
}
@override
Future<AuthResponse> login(LoginRequest request) async {
final response = await _api.login(request);
Future<AuthResponse> createSession(LoginRequest request) async {
final response = await _api.createSession(request);
await _tokenStorage.saveTokens(
access: response.accessToken,
refresh: response.refreshToken,
@@ -44,8 +46,8 @@ class AuthRepositoryImpl implements AuthRepository {
}
@override
Future<AuthResponse> refresh(String refreshToken) async {
final response = await _api.refresh(
Future<AuthResponse> refreshSession(String refreshToken) async {
final response = await _api.refreshSession(
RefreshRequest(refreshToken: refreshToken),
);
await _tokenStorage.saveTokens(
@@ -56,10 +58,10 @@ class AuthRepositoryImpl implements AuthRepository {
}
@override
Future<void> logout() async {
Future<void> deleteSession() async {
final refreshToken = await _tokenStorage.getRefreshToken();
if (refreshToken != null) {
await _api.logout(LogoutRequest(refreshToken: refreshToken));
await _api.deleteSession(LogoutRequest(refreshToken: refreshToken));
}
await _tokenStorage.clear();
}
@@ -35,32 +35,12 @@ class AuthResponse {
}
}
class SignupStartResponse {
final String status;
class VerificationCreateResponse {
final String email;
final String message;
const SignupStartResponse({
required this.status,
required this.email,
required this.message,
});
const VerificationCreateResponse({required this.email});
factory SignupStartResponse.fromJson(Map<String, dynamic> json) {
return SignupStartResponse(
status: json['status'] as String,
email: json['email'] as String,
message: json['message'] as String,
);
}
}
class SignupResendResponse {
final String message;
const SignupResendResponse({required this.message});
factory SignupResendResponse.fromJson(Map<String, dynamic> json) {
return SignupResendResponse(message: json['message'] as String);
factory VerificationCreateResponse.fromJson(Map<String, dynamic> json) {
return VerificationCreateResponse(email: json['email'] as String);
}
}
@@ -17,7 +17,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
final refreshToken = await _repository.getRefreshToken();
if (refreshToken != null) {
try {
final response = await _repository.refresh(refreshToken);
final response = await _repository.refreshSession(refreshToken);
emit(
AuthAuthenticated(
user: AuthUser(id: response.user.id, email: response.user.email),
@@ -25,7 +25,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
);
return;
} catch (_) {
await _repository.logout();
await _repository.deleteSession();
}
}
emit(AuthUnauthenticated());
@@ -39,7 +39,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthLoggedOut event,
Emitter<AuthState> emit,
) async {
await _repository.logout();
await _repository.deleteSession();
emit(AuthUnauthenticated());
}
}
@@ -59,7 +59,7 @@ class LoginCubit extends Cubit<LoginState> {
emit(state.copyWith(status: FormzSubmissionStatus.inProgress));
try {
final response = await _repository.login(
final response = await _repository.createSession(
LoginRequest(email: state.email.value, password: state.password.value),
);
emit(state.copyWith(status: FormzSubmissionStatus.success));
@@ -99,7 +99,7 @@ class RegisterCubit extends Cubit<RegisterState> {
emit(state.copyWith(status: FormzSubmissionStatus.inProgress));
try {
final response = await _repository.signupStart(
final response = await _repository.createVerification(
SignupStartRequest(
username: state.username.value,
email: state.email.value,
@@ -132,7 +132,7 @@ class RegisterCubit extends Cubit<RegisterState> {
emit(state.copyWith(status: FormzSubmissionStatus.inProgress));
try {
final response = await _repository.signupVerify(
final response = await _repository.verifyVerification(
SignupVerifyRequest(
email: state.pendingEmail!,
token: state.verificationCode.value,
@@ -166,7 +166,7 @@ class RegisterCubit extends Cubit<RegisterState> {
emit(state.copyWith(status: FormzSubmissionStatus.inProgress));
try {
await _repository.signupResend(
await _repository.resendVerification(
SignupResendRequest(email: state.pendingEmail!),
);
emit(
@@ -197,7 +197,7 @@ class RegisterCubit extends Cubit<RegisterState> {
);
try {
final response = await _repository.signupStart(
final response = await _repository.createVerification(
SignupStartRequest(
username: state.username.value,
email: state.email.value,
@@ -0,0 +1,38 @@
class UserResponse {
final String id;
final String username;
final String? avatarUrl;
final String? bio;
const UserResponse({
required this.id,
required this.username,
this.avatarUrl,
this.bio,
});
factory UserResponse.fromJson(Map<String, dynamic> json) {
return UserResponse(
id: json['id'] as String,
username: json['username'] as String,
avatarUrl: json['avatar_url'] as String?,
bio: json['bio'] as String?,
);
}
}
class UserUpdateRequest {
final String? username;
final String? avatarUrl;
final String? bio;
const UserUpdateRequest({this.username, this.avatarUrl, this.bio});
Map<String, dynamic> toJson() {
return {
if (username != null) 'username': username,
if (avatarUrl != null) 'avatar_url': avatarUrl,
if (bio != null) 'bio': bio,
};
}
}
@@ -0,0 +1,24 @@
import 'package:social_app/core/api/api_client.dart';
import 'models/user_response.dart';
class UsersApi {
final ApiClient _client;
static const _prefix = '/api/v1/users';
UsersApi(this._client);
Future<UserResponse> getMe() async {
final response = await _client.get('$_prefix/me');
return UserResponse.fromJson(response.data);
}
Future<UserResponse> updateMe(UserUpdateRequest request) async {
final response = await _client.patch('$_prefix/me', data: request.toJson());
return UserResponse.fromJson(response.data);
}
Future<UserResponse> getByUsername(String username) async {
final response = await _client.get('$_prefix/$username');
return UserResponse.fromJson(response.data);
}
}
@@ -0,0 +1,7 @@
import 'models/user_response.dart';
abstract class UsersRepository {
Future<UserResponse> getMe();
Future<UserResponse> updateMe(UserUpdateRequest request);
Future<UserResponse> getByUsername(String username);
}
@@ -0,0 +1,24 @@
import 'users_api.dart';
import 'users_repository.dart';
import 'models/user_response.dart';
class UsersRepositoryImpl implements UsersRepository {
final UsersApi _api;
UsersRepositoryImpl({required UsersApi api}) : _api = api;
@override
Future<UserResponse> getMe() {
return _api.getMe();
}
@override
Future<UserResponse> updateMe(UserUpdateRequest request) {
return _api.updateMe(request);
}
@override
Future<UserResponse> getByUsername(String username) {
return _api.getByUsername(username);
}
}