# Guide de Mise en Place des APIs avec Django REST Framework

Ce guide détaille la mise en place d'une architecture d'API RESTful robuste et modulaire pour votre projet Django, en se concentrant particulièrement sur la gestion centralisée des routes.

## 1. Introduction

[Django REST Framework (DRF)](https://www.django-rest-framework.org/) est un toolkit puissant et flexible pour construire des APIs web. Il s'intègre parfaitement avec Django, permettant de transformer rapidement vos modèles en endpoints API.

## 2. Prérequis

Assurez-vous que les packages nécessaires sont installés dans votre environnement virtuel :

```bash
pip install djangorestframework djangorestframework-simplejwt djoser
```

Et qu'ils sont ajoutés à votre `INSTALLED_APPS` dans `config/settings.py` :

```python
# config/settings.py
INSTALLED_APPS = [
    # ...
    "rest_framework",
    "rest_framework_simplejwt",
    "djoser",
    # ...
]
```

## 3. Concepts Clés

### 3.1. Serializers

Les serializers de DRF convertissent les instances de modèles Django en formats de données (comme JSON) et vice-versa. Ils gèrent également la validation des données.

*   **Exemple (`apps/customers/api/serializers.py`)**:
    ```python
    from rest_framework import serializers
    from ..models import Customer

    class CustomerSerializer(serializers.ModelSerializer):
        user_email = serializers.ReadOnlyField(source='user.email')

        class Meta:
            model = Customer
            fields = ['id', 'user_email', 'address', 'phone_number', 'birth_date', 'is_member']
            read_only_fields = ['id', 'is_member']
    ```

### 3.2. ViewSets

Les ViewSets fournissent une implémentation des opérations CRUD (Create, Retrieve, Update, Delete) pour un modèle donné, réduisant considérablement la quantité de code à écrire. Ils sont généralement utilisés avec des routeurs.

*   **Exemple (`apps/customers/api/views.py`)**:
    ```python
    from rest_framework import viewsets
    from ..models import Customer
    from .serializers import CustomerSerializer

    class CustomerViewSet(viewsets.ReadOnlyModelViewSet):
        queryset = Customer.objects.all()
        serializer_class = CustomerSerializer
    ```

## 4. Structure de l'API : Le Sous-répertoire `api`

Pour maintenir une architecture modulaire et propre, tout le code lié à l'API (serializers, vues, URLs) d'une application réside dans un sous-répertoire `api` au sein de cette application.

```
mon-projet/
├── apps/
│   ├── customers/
│   │   ├── models.py
│   │   ├── admin.py
│   │   └── api/             # <-- Nouveau répertoire
│   │       ├── __init__.py
│   │       ├── serializers.py
│   │       ├── views.py
│   │       └── urls.py
│   ├── members/
│   │   └── api/
│   │       ├── ...
│   └── ...
└── config/
    └── urls.py              # Fichier d'URL racine
```

## 5. Gestion Centralisée des Routes avec un Routeur Global

### 5.1. Le Problème des Routeurs Multiples

Si chaque application définit son propre `DefaultRouter` et que toutes sont incluses directement sous le même préfixe (`path("api/", include('app.api.urls'))`), la racine de l'API (`/api/`) n'affichera que les endpoints du *premier* routeur rencontré. Les autres endpoints existeront, mais ne seront pas listés à la racine, ce qui rend la découverte difficile.

### 5.2. La Solution : Un Routeur Global Unique

Pour avoir une racine d'API complète et cohérente, nous utilisons une seule instance de `DefaultRouter` au niveau du projet (`config/urls.py`) et y enregistrons tous les ViewSets de toutes les applications.

### 5.3. Implémentation Détaillée

#### Étape 1 : Fichiers `apps/<app_name>/api/urls.py`

Chaque fichier `urls.py` d'API d'application ne doit plus créer son propre routeur ni définir `urlpatterns`. Au lieu de cela, il doit exporter une fonction qui prend une instance de routeur en paramètre et y enregistre les ViewSets de l'application.

*   **Exemple (`apps/customers/api/urls.py`)**:
    ```python
    # apps/customers/api/urls.py
    from .views import CustomerViewSet

    def register_api_endpoints(router):
        router.register(r'customers', CustomerViewSet, basename='customer')
    ```

*   **Exemple (`apps/banking/api/urls.py`)**:
    ```python
    # apps/banking/api/urls.py
    from .views import AccountViewSet, TransactionViewSet

    def register_api_endpoints(router):
        router.register(r'banking/accounts', AccountViewSet, basename='account')
        router.register(r'banking/transactions', TransactionViewSet, basename='transaction')
    ```
    *Note : Nous avons choisi de préfixer les endpoints avec le nom de l'application (ex: `banking/accounts`) pour une meilleure organisation et pour éviter les conflits de noms entre applications.* 

#### Étape 2 : Fichier `config/urls.py` (Le Routeur Global)

Le fichier `config/urls.py` est le point central où le routeur global est créé et où tous les endpoints sont enregistrés.

```python
# config/urls.py
from django.contrib import admin
from django.urls import include, path
from rest_framework.routers import DefaultRouter

# 1. Importez les fonctions register_api_endpoints de chaque application
from apps.customers.api.urls import register_api_endpoints as register_customers_api
from apps.members.api.urls import register_api_endpoints as register_members_api
from apps.banking.api.urls import register_api_endpoints as register_banking_api
from apps.shares.api.urls import register_api_endpoints as register_shares_api
from apps.credits.api.urls import register_api_endpoints as register_credits_api

# 2. Créez une instance unique du routeur global
router = DefaultRouter()

# 3. Enregistrez tous les ViewSets avec le routeur global
register_customers_api(router)
register_members_api(router)
register_banking_api(router)
register_shares_api(router)
register_credits_api(router)

urlpatterns = [
    path("admin/", admin.site.urls),
    # 4. Incluez les URLs du routeur global sous le préfixe /api/
    path("api/", include(router.urls)),
    
    # 5. Incluez les URLs d'authentification de Djoser séparément
    # (Djoser gère ses propres routes et n'utilise pas le DefaultRouter global)
    path("api/auth/", include('apps.authentication.api.urls')),
]
```

### 5.4. URLs Finales (Exemples)

Avec cette configuration, vos URLs d'API seront claires et bien structurées :

*   `/api/customers/`
*   `/api/members/`
*   `/api/banking/accounts/`
*   `/api/banking/transactions/`
*   `/api/shares/share-types/`
*   `/api/shares/share-subscriptions/`
*   `/api/shares/share-payments/`
*   `/api/credits/credit-products/`
*   `/api/credits/loan-applications/`
*   `/api/credits/loans/`
*   `/api/credits/repayment-schedules/`
*   `/api/credits/repayments/`
*   `/api/auth/users/` (Djoser)
*   `/api/auth/jwt/create/` (Djoser/Simple JWT)

## 6. Authentification et Permissions (Configuration `settings.py`)

Pour sécuriser votre API, assurez-vous que votre `settings.py` contient la configuration suivante pour DRF, Simple JWT et Djoser :

```python
# config/settings.py
# ...

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated', # Exige une authentification par défaut
    )
}

from datetime import timedelta
SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    "ROTATE_REFRESH_TOKENS": True, # Optionnel: pour une sécurité accrue
    "BLACKLIST_AFTER_ROTATION": True, # Optionnel: pour invalider l'ancien refresh token
}

DJOSER = {
    'PASSWORD_RESET_CONFIRM_URL': '#/password/reset/confirm/{uid}/{token}',
    'USERNAME_RESET_CONFIRM_URL': '#/username/reset/confirm/{uid}/{token}',
    'ACTIVATION_URL': '#/activate/{uid}/{token}',
    'SEND_ACTIVATION_EMAIL': False, # À changer pour True en production avec un service d'email
    'USER_CREATE_PASSWORD_RETYPE': True,
    'PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND': True,
    'LOGIN_FIELD': 'email',
    'SERIALIZERS': {
        'user_create': 'authentication.api.serializers.UserCreateSerializer',
        'user': 'authentication.api.serializers.UserSerializer',
        'current_user': 'authentication.api.serializers.UserSerializer',
    },
}

# ...
```

## 7. Tester l'API

1.  **Démarrez le serveur de développement** :
    ```bash
    /path/to/your/venv/bin/python manage.py runserver
    ```

2.  **Accédez à la racine de l'API** dans votre navigateur : `http://127.0.0.1:8000/api/`. Vous devriez voir tous les endpoints listés.

3.  **Testez l'authentification (avec Postman, Insomnia ou `curl`)** :
    *   **Inscription** (`POST /api/auth/users/`) :
        ```json
        {
            "email": "test@example.com",
            "username": "testuser",
            "password": "your_strong_password",
            "re_password": "your_strong_password"
        }
        ```
    *   **Connexion** (`POST /api/auth/jwt/create/`) :
        ```json
        {
            "email": "test@example.com",
            "password": "your_strong_password"
        }
        ```
        Cela vous retournera un `access` token et un `refresh` token.

4.  **Testez un endpoint sécurisé** (ex: `GET /api/customers/`) :
    *   Dans l'en-tête de la requête, ajoutez `Authorization: Bearer <votre_access_token>`.
    *   Vous devriez pouvoir accéder aux données (si vous avez les permissions nécessaires).

## Conclusion

Cette configuration fournit une base solide et évolutive pour votre API, en respectant les bonnes pratiques de Django et de Django REST Framework. Elle centralise la gestion des routes, organise le code de manière modulaire et intègre un système d'authentification moderne.
