Application Angular standalone pour gérer une collection de cartes de monstres avec authentification.
📺 Projet basé sur le tutoriel : SimpleTechProd - API REST avec HttpClient
🔗 Backend GitLab :
git@gitlab.com:simpletechprod1/playing_cards_backend.git
- Architecture du projet
- Prérequis
- Installation
- Lancer l'application
- Fonctionnement de l'application
- Commandes Angular CLI
- Structure des dossiers
src/app/
├── components/ # Composants réutilisables
│ ├── playing-card/ # Carte de monstre
│ ├── search-bar/ # Barre de recherche
│ └── delete-monster-confirmation-dialog/
├── pages/ # Pages de l'application
│ ├── login/ # Page de connexion
│ ├── monster-list/ # Liste des monstres
│ ├── monster/ # Formulaire création/édition
│ └── not-found/ # Page 404
├── services/ # Services (API calls)
│ ├── monster/ # CRUD monstres
│ └── login/ # Authentification
├── guards/ # Guards de navigation
│ └── is-logged-in/ # Vérifie si l'utilisateur est connecté
├── interceptors/ # HTTP Interceptors
│ └── auth-token/ # Ajoute le token aux requêtes
├── model/ # Classes Model
├── interfaces/ # Interfaces TypeScript
└── utils/ # Utilitaires et constantes
- Node.js (v18 ou supérieur)
- npm (v9 ou supérieur)
- Angular CLI (v19 ou supérieur)
# Installer Angular CLI globalement
npm install -g @angular/cli# Backend Django
git clone git@gitlab.com:simpletechprod1/playing_cards_backend.git
cd playing_cards_backend
# Suivre les instructions du README backend pour :
# - Créer l'environnement virtuel
# - Installer les dépendances
# - Créer un superuser
# - Lancer le serveur
# Frontend Angular (votre projet)
cd ..
git clone <url-de-votre-projet-frontend>
cd playing-cards-frontend
npm install# Dans le dossier backend
cd playing_cards_backend
source .venv/bin/activate
# Si première fois, créer un superuser
./manage.py createsuperuser
# Username: votre_nom
# Email: votre@email.com
# Password: votre_mot_de_passe
# Lancer le serveur
./manage.py runserverLe backend sera accessible sur http://localhost:8000
Endpoints disponibles :
POST /sessions/login/- ConnexionGET /sessions/logout/- DéconnexionGET /sessions/me/- Informations utilisateurGET /monsters/- Liste des monstresPOST /monsters/- Créer un monstreGET /monsters/:id/- Détails d'un monstrePUT /monsters/:id/- Modifier un monstreDELETE /monsters/:id/- Supprimer un monstre
Admin Django : http://localhost:8000/admin
Swagger API : http://localhost:8000/api/swagger-ui/
# Dans le dossier frontend
ng serve
# Ou pour ouvrir automatiquement le navigateur
ng serve --openL'application sera accessible sur http://localhost:4200
// LoginService (services/login/login.ts)
login(credentials: LoginRequest): Observable<LoginResponse> {
return this.http.post<LoginResponse>(BASE_URL + 'login/', credentials).pipe(
tap(response => {
// Stocke le token dans localStorage
localStorage.setItem('token', response.token);
// Met à jour le signal user
this.user.set(response.user);
})
);
}Flow d'authentification :
- L'utilisateur saisit ses identifiants sur
/login - Le service envoie une requête POST à
/sessions/login/ - Le backend retourne un token et les infos utilisateur
- Le token est stocké dans
localStorage - L'intercepteur ajoute automatiquement ce token à toutes les requêtes HTTP
// auth-token-interceptor.ts
export const authTokenInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('token');
if (token) {
const clonedRequest = req.clone({
setHeaders: {
Authorization: `Token ${token}`
}
});
return next(clonedRequest);
}
return next(req);
};L'intercepteur ajoute automatiquement le header Authorization: Token xxx à chaque requête HTTP.
// is-logged-in-guard.ts
export const isLoggedInGuard: CanActivateFn = (route, state) => {
const loginService = inject(LoginService);
const router = inject(Router);
if (loginService.user()) {
return true; // Utilisateur connecté
}
// Redirige vers /login si non connecté
return router.createUrlTree(['/login']);
};Utilisé dans les routes :
{
path: 'monster',
component: MonsterComponent,
canActivate: [isLoggedInGuard] // Protège cette route
}L'application utilise les signals d'Angular (nouvelle API) :
// Dans LoginService
user = signal<User | null>(null);
// Dans MonsterListComponent
monsters = toSignal(this.monsterService.getAll());
search = model('');
filteredMonsters = computed(() => {
return this.monsters()?.filter(
monster => monster.name.includes(this.search())
) ?? [];
});// MonsterService
getAll(): Observable<Monster[]> // GET /monsters/
get(id: number): Observable<Monster> // GET /monsters/:id/
add(monster: Monster): Observable<Monster> // POST /monsters/
update(monster: Monster): Observable<Monster> // PUT /monsters/:id/
delete(id: number): Observable<void> // DELETE /monsters/:id/# Composant standalone simple
ng generate component pages/my-page
# Composant standalone avec routing
ng generate component pages/my-page --standalone
# Composant dans un sous-dossier
ng generate component components/my-component
# Avec options (sans fichier de test, inline styles)
ng generate component my-component --skip-tests --inline-style# Service simple
ng generate service services/my-service/my-service
# Service avec providedIn root
ng generate service services/api/api --skip-tests# Guard fonctionnel (recommandé)
ng generate guard guards/auth/auth
# Choisir le type : CanActivate, CanDeactivate, etc.# Interceptor fonctionnel
ng generate interceptor interceptors/logging/logging# Interface TypeScript
ng generate interface interfaces/user
# Class TypeScript
ng generate class model/monster# Pipe personnalisé
ng generate pipe pipes/custom-date# Directive
ng generate directive directives/highlight# Build pour production
ng build --configuration production
# Lancer les tests
ng test
# Lancer les tests e2e
ng e2e
# Linter le code
ng lint
# Analyser le bundle
ng build --stats-json
npx webpack-bundle-analyzer dist/stats.jsonsrc/
├── app/
│ ├── components/ # Composants réutilisables (dumb components)
│ │ ├── playing-card/
│ │ ├── search-bar/
│ │ └── modal/
│ ├── pages/ # Pages principales (smart components)
│ │ ├── login/
│ │ ├── home/
│ │ └── monster/
│ ├── services/ # Services Angular
│ │ ├── monster/
│ │ └── auth/
│ ├── guards/ # Route guards
│ ├── interceptors/ # HTTP interceptors
│ ├── directives/ # Directives personnalisées
│ ├── pipes/ # Pipes personnalisés
│ ├── model/ # Classes Model
│ ├── interfaces/ # Interfaces TypeScript
│ ├── utils/ # Fonctions utilitaires
│ ├── constants/ # Constantes
│ └── enums/ # Enumerations
├── assets/ # Images, fonts, etc.
├── environments/ # Configuration par environnement
└── styles/ # Styles globaux
- Composants :
my-component.ts,my-component.html,my-component.css - Services :
my-service.service.ts - Guards :
auth.guard.ts - Interceptors :
logging.interceptor.ts - Interfaces :
user.interface.tsouuser.ts - Models :
monster.model.tsoumonster.ts
- Composants :
MyComponent(PascalCase) - Services :
MyService - Interfaces :
IUserouUser - Enums :
MonsterType
- camelCase :
myVariable,getUserName() - Constantes :
SNAKE_CASEoucamelCase
Le token est actuellement stocké dans localStorage. Pour plus de sécurité en production :
- Utiliser des HTTP-only cookies
- Implémenter un refresh token
- Ajouter une expiration au token
Le backend Django doit autoriser les requêtes depuis http://localhost:4200 :
# settings.py
CORS_ALLOWED_ORIGINS = [
"http://localhost:4200",
]- Vérifier que le token est stocké :
localStorage.getItem('token') - Vérifier que l'interceptor ajoute le header
- Vérifier le format du token attendu par le backend
- Vérifier l'import dans
app.routes.ts - S'assurer d'importer le composant et non la classe model
- Vider le cache du navigateur (Ctrl + Shift + R)
- Utiliser
::ng-deeppour les composants Material - Désactiver l'encapsulation :
encapsulation: ViewEncapsulation.None - Utiliser des styles globaux dans
styles.css
- Documentation Angular
- Angular CLI
- Angular Material
- RxJS
- Tutoriel SimpleTechProd - API REST avec HttpClient
- Backend Playing Cards - GitLab
Ce projet suit la série de tutoriels SimpleTechProd sur Angular et l'intégration d'API REST.
- ✅ Composants Angular standalone
- ✅ Routing et navigation
- ✅ HttpClient et appels API
- ✅ Authentification JWT
- ✅ HTTP Interceptors
- ✅ Route Guards
- ✅ Signals Angular (nouvelle API)
- ✅ Reactive Forms
- ✅ Angular Material
- Introduction à Angular
- Composants et templates
- Services et injection de dépendances
- Routing
- API REST avec HttpClient ← Ce projet
- Authentification
- Guards et interceptors
Ce projet est un exemple éducatif. Utilisez-le librement pour apprendre Angular !
Pour contribuer :
- Fork le projet
- Créer une branche (
git checkout -b feature/AmazingFeature) - Commit les changements (
git commit -m 'Add AmazingFeature') - Push (
git push origin feature/AmazingFeature) - Ouvrir une Pull Request