5a. API - Yolino/t211-dbox-fm GitHub Wiki

Résumé coaching 5.a

+ Les choix de conception de l'API sont expliqués sur le Wiki : Ressources exposées, choix de nommage, technologie utilisée… Les noms et conventions utilisés sont cohérents.
+ La documentation de l'API est accessible depuis le Wiki.  Elle est claire et bien organisée. 
"Pour chaque ressource, une section détaille au moins : 
* la description de la ressource
* les endpoints associés et les méthodes pour y accéder
* les éventuels paramètres disponibles
* un exemple de requête
* un exemple de réponse"
+ L'API respecte globalement les principes REST
+ Le groupe peut présenter un exemple fonctionnel de endpoint de l'API (par ex. avec curl).  Tous les étudiants peuvent en expliquer le fonctionnement.  
+ Le groupe utilise un outil adéquat dédié pour tester son API lors du développement

1. Choix de conception pour l'API

Comme mentionné dans nos choix technologiques, notre API est hybride et utilise deux technologies différentes :

  • GraphQL : permet la majorité des queries de données sous différents formats selon le cas d'utilisation, et l'intégralité des mutations pour les opérations qui modifient l'état de la base de données

  • REST : nous sert pour récupérer les fichiers (audio et images) de manière plus efficace que GraphQL, mais également pour la récupération du programme "radio" par notre station réalisée dans le cadre du projet d'électronique, étant donné que le Raspberry Pi Pico n'a pas de client GraphQL intégré

2a. Documentation de l'API GraphQL

Chaque application possède individuellement son système de query et mutation :

Types

PublicationType

  • id: ID
  • title: String
  • author: ReportedUserType
  • cover: String (URL de l'image de couverture)
  • tag: TagType
  • description: String
  • viewCount: Int
  • voteCount: Int
  • createdAt: DateTime
  • isBanned: Boolean
  • visitorVote: String
  • isOwner: Boolean

ReportedUserType

  • id: ID
  • username: String
  • isActive: Boolean
  • reportCount: Int

ReportedPublicationType

  • id: ID
  • title: String
  • author: ReportedUserType
  • cover: String
  • description: String
  • isBanned: Boolean
  • reportCount: Int

ReportedCommentType

  • id: ID
  • publication: ReportedPublicationType
  • author: ReportedUserType
  • text: String
  • isBanned: Boolean
  • reportCount: Int

SchedulingType

  • id: ID
  • publication: ReportedPublicationType
  • time: DateTime

TagType

  • id: ID
  • name: String
  • publicationSet: [ReportedPublicationType!]

CommentType

  • id: ID
  • publication: ReportedPublicationType
  • author: ReportedUserType
  • parent: ReportedCommentType
  • text: String
  • createdAt: DateTime
  • isBanned: Boolean

ProfileType

  • user: UserType
  • publications: [PublicationType!]
  • comments: [CommentType!]
  • isSelf: Boolean

UserType

  • id: ID
  • username: String
  • email: String
  • isActive: Boolean

PrivilegesType

  • isLoggedIn: Boolean
  • isModerator: Boolean

ReportedContentType

  • users: [ReportedUserType]
  • publications: [ReportedPublicationType]
  • comments: [ReportedCommentType]
  • totalCount: Int

PublicationPageType

  • publications: [PublicationType!]
  • hasNextPage: Boolean

Query

schedule(date: Date): [SchedulingType]

  • Renvoie la liste des publications planifiées pour une date donnée.
  • Réponse : [SchedulingType]
  • Erreurs :
    • Aucune date fournie renvoie tous les éléments planifiés

reporters(reportedId: Int!, contentType: String!): [ReportUnion]

  • Renvoie la liste des rapports pour un contenu donné.
  • Réponse : [ReportUnion]

reportedContent: ReportedContentType

  • Récupère tous les contenus signalés (utilisateurs, publications, commentaires).
  • Réponse : ReportedContentType

bannedContent: ReportedContentType

  • Récupère tous les contenus bannis.
  • Réponse : ReportedContentType

publication(id: Int!): PublicationType

  • Renvoie une publication unique par son ID.
  • Réponse : PublicationType
  • Erreurs :
    • La publication n'existe pas
    • L'utilisateur n'est pas autorisé à consulter une publication bannie

publicationPage(start: Int, count: Int, orderBy: String, author: String): PublicationPageType

  • Renvoie une page paginée de publications selon les critères.
  • Réponse : PublicationPageType

commentsByPublication(publicationId: Int!): [CommentType!]

  • Renvoie tous les commentaires liés à une publication.
  • Réponse : [CommentType!]

publicationLookup(title: String!): [PublicationType!]

  • Recherche les publications contenant un titre donné.
  • Réponse : [PublicationType!]

tags: [TagType]

  • Liste tous les tags disponibles.
  • Réponse : [TagType]

me: PrivilegesType

  • Renvoie les privilèges de l'utilisateur courant.
  • Réponse : PrivilegesType

profile(username: String): ProfileType

  • Renvoie le profil public d'un utilisateur.
  • Réponse : ProfileType

userLookup(name: String!): [UserType!]

  • Recherche des utilisateurs par nom d'utilisateur.
  • Réponse : [UserType!]

Mutation

createPublication(title: String!, cover: Upload, tag: Int!, description: String!, audio: Upload!)

  • Crée une nouvelle publication.
  • Paramètres :
    • title : Titre de la publication
    • cover : Fichier image de couverture (optionnel)
    • tag : ID du tag
    • description : Description de la publication
    • audio : Fichier audio
  • Réponse : PublicationType
  • Erreurs :
    • Utilisateur non authentifié
    • Le tag n'existe pas
    • Format d’image invalide
    • Format audio invalide

updatePublication(publicationId: Int!, title: String, description: String, tag: Int, cover: Upload, removeCover: Boolean!)

  • Met à jour une publication existante.
  • Paramètres :
    • publicationId : ID de la publication
    • title : Nouveau titre (optionnel)
    • description : Nouvelle description (optionnel)
    • tag : Nouveau tag (optionnel)
    • cover : Nouvelle image de couverture (optionnelle)
    • removeCover : Indique si la couverture doit être supprimée
  • Réponse : UpdatePublication
  • Erreurs :
    • Publication introuvable ou non autorisée
    • Le tag n'existe pas

deletePublication(publicationId: Int!)

  • Supprime une publication existante.
  • Paramètres :
    • publicationId : ID de la publication
  • Réponse : DeletePublication
  • Erreurs :
    • Utilisateur non autorisé
    • Publication introuvable

createVote(publicationId: Int!, type: Int!)

  • Crée un vote sur une publication.
  • Paramètres :
    • publicationId : ID de la publication
    • type : Type de vote (ex: 1 = upvote, -1 = downvote)
  • Réponse : CreateVote
  • Erreurs :
    • Publication introuvable
    • Utilisateur non authentifié

updateVote(publicationId: Int!, type: Int!)

  • Met à jour le type d’un vote existant.
  • Paramètres :
    • publicationId : ID de la publication
    • type : Nouveau type de vote
  • Réponse : UpdateVote
  • Erreurs :
    • Aucun vote existant pour cette publication

deleteVote(publicationId: Int!)

  • Supprime un vote d’une publication.
  • Paramètres :
    • publicationId : ID de la publication
  • Réponse : DeleteVote
  • Erreurs :
    • Aucun vote à supprimer

createView(publicationId: Int!)

  • Incrémente le compteur de vues d’une publication.
  • Paramètres :
    • publicationId : ID de la publication
  • Réponse : CreateView

createComment(publication: Int!, text: String!, parent: Int)

  • Crée un commentaire sur une publication.
  • Paramètres :
    • publication : ID de la publication
    • text : Contenu du commentaire
    • parent : ID du commentaire parent (optionnel)
  • Réponse : CreateComment
  • Erreurs :
    • Utilisateur non authentifié
    • Publication introuvable

updateComment(commentId: Int!, text: String!)

  • Modifie un commentaire existant.
  • Paramètres :
    • commentId : ID du commentaire
    • text : Nouveau texte du commentaire
  • Réponse : UpdateComment
  • Erreurs :
    • Commentaire introuvable
    • Non autorisé

deleteComment(commentId: Int!)

  • Supprime un commentaire existant.
  • Paramètres :
    • commentId : ID du commentaire
  • Réponse : DeleteComment
  • Erreurs :
    • Non autorisé à supprimer ce commentaire

createScheduling(publicationId: Int!, time: DateTime!)

  • Programme une publication à une date précise.
  • Paramètres :
    • publicationId : ID de la publication
    • time : Date et heure de publication
  • Réponse : CreateScheduling

deleteScheduling(schedulingId: Int!)

  • Supprime une planification de publication.
  • Paramètres :
    • schedulingId : ID de la planification
  • Réponse : DeleteScheduling

createReport(contentType: String!, reportedId: Int!)

  • Signale un contenu (utilisateur, publication ou commentaire).
  • Paramètres :
    • contentType : Type de contenu (e.g. "user", "publication")
    • reportedId : ID du contenu signalé
  • Réponse : CreateReport

reviewReport(isSafe: Boolean!, reportType: String!, reportedId: Int!)

  • Marque un signalement comme traité.
  • Paramètres :
    • isSafe : Si le contenu est jugé acceptable
    • reportType : Type du rapport (user/publication/comment)
    • reportedId : ID du contenu signalé
  • Réponse : ReviewReport

unbanContent(bannedId: Int!, contentType: String!)

  • Rétablit un contenu banni.
  • Paramètres :
    • bannedId : ID du contenu
    • contentType : Type de contenu
  • Réponse : UnbanContent

createUser(email: String!, password: String!, username: String!)

  • Crée un nouvel utilisateur.
  • Paramètres :
    • email : Adresse e-mail
    • password : Mot de passe
    • username : Nom d'utilisateur
  • Réponse : CreateUser

loginUser(username: String!, password: String!)

  • Connecte un utilisateur.
  • Paramètres :
    • username : Nom d'utilisateur
    • password : Mot de passe
  • Réponse : LoginUser

logoutUser

  • Déconnecte l'utilisateur actuel.
  • Réponse : LogoutUser

updateUsername(newUsername: String!, password: String!)

  • Met à jour le nom d’utilisateur.
  • Paramètres :
    • newUsername : Nouveau nom
    • password : Mot de passe actuel
  • Réponse : UpdateUsername

updatePassword(currentPassword: String, newPassword: String)

  • Change le mot de passe de l'utilisateur.
  • Paramètres :
    • currentPassword : Mot de passe actuel (optionnel)
    • newPassword : Nouveau mot de passe
  • Réponse : UpdatePassword

2b. Documentation de l'API REST

  • GET /audio/{pk}/

    • Récupère le fichier audio associé à une publication.
    • URL: /audio/{pk}/
    • Paramètres d'URL:
      • pk: ID de la publication (entier)
    • Réponse réussie:
      • Code: 200 OK
      • Contenu: Flux du fichier audio
      • Type de contenu: audio/mpeg
    • Réponses d'erreur:
      • Code: 404 Not Found
        • Contenu: {"detail": "Audio not found"}
        • Condition: La publication avec l'ID spécifié n'existe pas
      • Code: 403 Forbidden
        • Contenu: {"detail": "This Publication has been banned. You can no longer access it"}
        • Condition: La publication a été bannie
  • GET /schedule/

    • Récupère la liste complète des programmations.
    • URL: /schedule/
    • Paramètres: Aucun
    • Réponse réussie:
      • Code: 200 OK
      • Contenu: Liste des objets de programmation
      • Format: [{"id": integer, "publication": integer, "time": datetime}, ...]

3. Outils utilisés pour développer et tester l'API

  • Frontend : Apollo Client est le module utilisé par le client pour envoyer les queries/mutations et traiter leurs réponses
  • Backend : Graphene Django est employé du côté serveur pour définir le schéma GraphQL. Dans le cadre du serveur de développement servi par Django, Graphene nous offre un environnement de test du schéma grâce à GraphiQL, disponible en localhost:8000/graphql