Overview
UsuarioRepository is an abstract class that defines the contract for user authentication and registration operations in the Karma Ecommerce application. It follows the Repository Pattern from Domain-Driven Design (DDD), providing an abstraction layer between the domain logic and data access implementation.
Why Abstract?
The repository is defined as an abstract class to:
Decouple domain logic from infrastructure : The domain layer doesn’t depend on specific HTTP implementations
Enable dependency injection : Angular’s DI system can inject different implementations
Facilitate testing : Mock implementations can be easily injected for unit tests
Follow SOLID principles : Dependency Inversion Principle (DIP) - depend on abstractions, not concretions
Source Code
import { Observable } from "rxjs" ;
import { Usuario } from "../models/usuario" ;
export abstract class UsuarioRepository {
abstract loginUsuario ( usuario : string , contrasena : string ) : Observable < Usuario >;
abstract registrarUsuario ( usuario : string , contrasena : string ) : Observable < Usuario >;
}
Location : src/app/usuario/domain/repositories/usuario.repository.ts
Methods
loginUsuario()
Authenticates a user with their credentials and returns user information.
abstract loginUsuario ( usuario : string , contrasena : string ): Observable < Usuario >
The username for authentication
Returns an RxJS Observable that emits a Usuario object upon successful authentication
registrarUsuario()
Registers a new user in the system.
abstract registrarUsuario ( usuario : string , contrasena : string ): Observable < Usuario >
The desired username for the new account
The password for the new account
Returns an RxJS Observable that emits the newly created Usuario object
Implementation
AuthService
The concrete implementation of UsuarioRepository is provided by the AuthService class.
@ Injectable ({
providedIn: 'root' ,
})
export class AuthService implements UsuarioRepository {
private readonly BASE_URL = 'http://localhost:8080/'
constructor ( private httpClient : HttpClient ) { }
loginUsuario ( usuario : string , contrasena : string ) : Observable < Usuario > {
return this . httpClient . get < Usuario >(
` ${ this . BASE_URL } login/ ${ usuario } / ${ contrasena } `
);
}
registrarUsuario ( usuario : string , contrasena : string ) : Observable < Usuario > {
const body = { usuario , contrasena };
return this . httpClient . post < Usuario >(
` ${ this . BASE_URL } registro` ,
body ,
{ headers: { 'Content-Type' : 'application/json' } }
);
}
}
Location : src/app/usuario/infrastructure/services/auth-service.ts
Usage Examples
In Query Handlers (Login)
The LoginUserHandler uses the repository to authenticate users:
@ Injectable ()
export class LoginUserHandler {
constructor ( private usuarioRepository : UsuarioRepository ) {}
handle ( query : LoginUserQuery ) : Observable < Usuario > {
return this . usuarioRepository . loginUsuario (
query . usuario ,
query . contrasena
);
}
}
Location : src/app/usuario/application/usecases/queryHandlers/login-user.handler.ts
In Command Handlers (Registration)
The RegisterUserHandler uses the repository to register new users:
@ Injectable ()
export class RegisterUserHandler {
constructor ( private usuarioRepository : UsuarioRepository ) {}
handle ( command : RegisterUserCommand ) : Observable < Usuario > {
return this . usuarioRepository . registrarUsuario (
command . usuario ,
command . contrasena
);
}
}
Location : src/app/usuario/application/usecases/commandHandlers/register-user.handler.ts
Subscribing to Results
// Login example
usuarioRepository . loginUsuario ( 'john_doe' , 'password123' )
. subscribe ({
next : ( usuario : Usuario ) => {
console . log ( 'Login successful:' , usuario . id );
// Handle successful login
},
error : ( error ) => {
console . error ( 'Login failed:' , error );
// Handle login error
}
});
// Registration example
usuarioRepository . registrarUsuario ( 'jane_doe' , 'securePass456' )
. subscribe ({
next : ( usuario : Usuario ) => {
console . log ( 'User registered:' , usuario . usuario );
// Navigate to login or home page
},
error : ( error ) => {
console . error ( 'Registration failed:' , error );
// Show error message to user
}
});
Architecture Context
Repository Pattern Benefits
Separation of Concerns : Domain logic is isolated from data access details
Testability : Easy to mock for unit testing handlers
Flexibility : Can swap implementations (HTTP, localStorage, mock) without changing domain code
Single Responsibility : Repository only handles data access, handlers manage business logic
CQRS Integration
The repository is used by both:
Query Handlers : LoginUserHandler for read operations (authentication)
Command Handlers : RegisterUserHandler for write operations (user creation)
This aligns with the CQRS (Command Query Responsibility Segregation) pattern used throughout the application.
AuthService HTTP implementation of UsuarioRepository
Usuario Model User domain model definition
LoginUserHandler Query handler for user authentication
RegisterUserHandler Command handler for user registration
Type Definitions
// Usuario interface
interface Usuario {
id : number ;
usuario : string ;
contrasena : string ;
}
// Observable from RxJS
import { Observable } from "rxjs" ;
Error Handling
When using the repository methods, handle potential errors:
usuarioRepository . loginUsuario ( username , password )
. pipe (
catchError (( error : HttpErrorResponse ) => {
if ( error . status === 401 ) {
// Invalid credentials
return throwError (() => new Error ( 'Invalid username or password' ));
} else if ( error . status === 500 ) {
// Server error
return throwError (() => new Error ( 'Server error, please try again' ));
}
return throwError (() => error );
})
)
. subscribe ({
next : ( usuario ) => { /* Handle success */ },
error : ( err ) => { /* Handle error */ }
});