Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refacto : on sépare les API internes full calendar dans un autre namespace #4805

Merged
merged 2 commits into from
Nov 27, 2024

Conversation

AntoineGirard
Copy link
Member

@AntoineGirard AntoineGirard commented Nov 13, 2024

Review app

Contexte

Nous rencontrons régulièrement un bug lorsque l’utilisateur est déconnecté, mais qu’il a laissé un onglet ouvert avec la page de calendrier. Voir ici : #4803

En cherchant des pistes de solutions, je me suis aperçu que les 3 points d’API que nous utilisons pour envoyer les données à fullCalendar ont la même base que les contrôleurs qui rendent du HTML.

Ceci me pose un problème, notamment dans la gestion des erreurs. Dans le cas du bug mentionné ci-avant, j’aurais voulu pouvoir gérer spécifiquement un code 401 pour faire une action dans ce cas (par exemple rediriger l’utilisateur), or, je reçois une 302 qui redirige vers la page de connexion.
Le handleAjaxError est déclenché, car fullCalendar essaie de parser la réponse comme si c’était un JSON sauf qu’il s’agit ici du HTML de la page de connexion.

Solution

Proposition initiale qui a permis les échanges
  • On utilise un « BaseController » dédié aux API internes.
  • Vu que tout le namespace admin dans routes.rb est encapsulé dans un authenticate :agent j’ai fait le choix de sortir complétement ces 3 contrôleurs et de les mettre dans api/internal.
  • On écrit une méthode authenticate_agent! pour ce contrôleur qui retourne du JSON plutôt que de rediriger vers la page d’accueil en cas de problème d’authentification.
  • À la suite de ça, on peut maintenant gérer la 401 proprement dans agenda.js. C’est un exemple d’utilisation, nous n’avons pas encore décidé en terme produit si nous voulons ce reload, un message d’erreur spécifique, ou ne rien faire… La suite de la discussion sur ce sujet dans l’issue dédiée.
  • À terme nous pourrons gérer d’autres cas d’erreurs, ou faire en sorte d’envoyer une Sentry pour les cas non gérés, etc. Bref on s’ouvre le champ des possibles.

La proposition de solution est bien résmuée ici : #4805 (review)

Copy link
Contributor

@adipasquale adipasquale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ça me paraît être une bonne piste !

@@ -0,0 +1,39 @@
class Api::Internal::BaseController < ApplicationController
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

je trouve l’idée de scoper à Api::Internal bonne pour montrer qu’il s’agit ici d’endpoints XHR et pas classiques.

En revanche j’ai l’impression que la majorité du code présent ici est en fait spécifique à l’agenda agent :

  • l’authentification agent
  • les helper methods de time range et date range

Je me demande donc s’il ne vaudrait pas mieux appeler cette classe Api::Internal::Admin::Agenda::BaseController

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merci Antoine pour cette proposition qui lève des points de douleur, c'est cool d'en parler. 🙏

Pour ma part je ne suis pas convaincu que ce qui qualifie un endpoint HTTP d'API soit le format de la réponse. Dans le cas présent, nous avons deux façons d'afficher les plages d'un agent connecté : sur une page HTML, ou sur un fullcalendar JSON. Mais le contexte dans lequel nous voulons récupérer et afficher ces informations est le même : au sein de l'interface de notre application. C'est ce qui me pousse à vouloir garder ces endpoints proches en termes de namespace et de nommage.

Ceci étant dit, je trouve que dans notre application il est difficile de trouver quels sont les endpoints JSON et pas HTML. La preuve, pour trouver la liste, j'ai dû aller sur Skylight :

image

Je soutiens donc la démarche qui consiste à donner de la visibilité à ces endpoints JSON.

Et si j'ai bien compris cette PR répond aussi au besoin de pouvoir contrôler ce qu'il se passe en cas de HTTP 401pour une requête JSON, et je me demande si il n'y a pas d'autres solutions. Je vais faire des tests et revenir ici pour discuter en étant plus informé là-dessus.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello,

@francois-ferrandis est-ce que tu as pu avancer tes réflexions ou investigations sur le sujet ?

@victormours de nos dernières discussions à l’oral jeudi, tu semblais plutôt partant pour l’éjection proposée, mais tu avais une autre proposition de rangement pour les routes. On était sur :

  • Laisser les routes dans le fichier routes.rb plutôt que dans api.rb
  • Et tu étais plus partant d’un admin/api plutôt que api/internal/admin

C’est bien ça ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toutafé ! La motivation était que que j'ai l'impression que le fichier config/routes/api.rb et le namespace api sont utilisés pour des endpoints qui permettent à des partenaires extérieurs de s'Interfacer pour Programmer leurs Applications, alors que les routes du fichier config/routes.rb et de /admin sont notre interface web.

Ici le format des requêtes est du json, mais il s'agit bien de notre interface web, et pas d'une api extérieure qui nous connecte au reste du monde.
Une autre formulation de la même idée, c'est que les api habituelles sont "externes", donc qu'on ne veut pas les mélanger avec cette api "interne"

Copy link
Contributor

@francois-ferrandis francois-ferrandis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

J'ai jeté un coup d'œil rapide, merci pour la relance ! Je vais te donner ci-dessous ma vision qui je l'espère pourra aider à prendre des décisions, et je te fais entièrement confiance pour la suite ! 🤝

Je pense qu'il y a plusieurs problèmes qui peuvent être traités séparément :

  1. Les controllers qui gèrent un format JSON sont difficiles à identifier
  2. Nous ne parvenons pas à rediriger vers la page de login lorsqu'un appel FullCalendar est fait non connecté
  3. L'usage des alert ne fait plaisir à personne, il y a d'autres moyens plus agréables d'indiquer l'état du refresh

Le fait de déplacer les controllers dans un namespace "API" répond au problème 1, et même si j'ai chipoté sur la sémantique, franchement ça me va bien (la solution admin/api proposée par Victor me plaît).

Pour répondre au problème 2, on peut soit :

  • signaler le format de la requête au niveau route, par exemple en définissant namespace :agenda, defaults: { format: :json } à la ligne 166 de routes.rb
  • ajouter format: :json dans les URLs injectées dans la config FullCalendar (app/views/admin/agent_agendas/show.html.slim), pour ajouter .json à la fin (ex: /rdvs.json?param=...)

Devise va alors automatiquement renvoyer des 401 au format JSON, que l'on peut catcher dans notre callback JS pour rediriger vers la page de login.

Et pour le problème 3, c'est traitable complètement séparément, et y'a un petit boulot de recherche UI pour déterminer où et comment on affiche "Le dernier fetch des plages a échoué pour une raison inconnue, on va réessayer". En effet, normalement on ne doit afficher ça qu'en cas de 500 ou timeout, une fois qu'on a traité spécifiquement les autres cas (agent non connecté, ou connecté avec un compte non autorisé).

Copy link
Contributor

@victormours victormours left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AntoineGirard AntoineGirard force-pushed the feat/refacto-agenda-internal-api branch 2 times, most recently from 69f30c7 to ef3533f Compare November 25, 2024 14:53
@AntoineGirard AntoineGirard changed the title Refacto : on utilise un controleur de base dédié aux APIs internes Refacto : on sépare les API internes full calendar dans un autre namespcae Nov 25, 2024
@AntoineGirard AntoineGirard force-pushed the feat/refacto-agenda-internal-api branch from ef3533f to e964ebe Compare November 25, 2024 14:58
@AntoineGirard AntoineGirard marked this pull request as draft November 25, 2024 14:58

let(:organisation) { create(:organisation) }

context "with a signed in agent" do
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ici j’ai juste rajouté ce contexte pour pouvoir rajouter le cas où l’agent n’est pas connecté

@AntoineGirard AntoineGirard changed the title Refacto : on sépare les API internes full calendar dans un autre namespcae Refacto : on sépare les API internes full calendar dans un autre namespace Nov 25, 2024
@AntoineGirard AntoineGirard force-pushed the feat/refacto-agenda-internal-api branch from e964ebe to 8abe7af Compare November 25, 2024 15:08
@AntoineGirard
Copy link
Member Author

Merci @francois-ferrandis pour ta réponse très complète.

Effectivement j’étais passé un peu à côté du fait que devise pouvait gérer ça automatiquement en rajoutant l’info du format dans le fichier routes.rb.

J’ai fait une proposition de code basé sur nos échanges et tes conclusions. Je te laisse me dire ce que tu en penses.

Concernant la gestion de l’erreur côté front, on est assez ok avec Mehdi et Teo pour redirigé vers la page de connexion en cas de 401. Je suis moyen convaincu par le window.reload donc je l’ai sorti de la PR et je vais faire une proposition dans une autre PR.
Il était juste là à titre d’exemple pour montrer que ça fonctionne.

@AntoineGirard AntoineGirard marked this pull request as ready for review November 25, 2024 15:10
@AntoineGirard AntoineGirard force-pushed the feat/refacto-agenda-internal-api branch from 8abe7af to 71bf013 Compare November 25, 2024 15:10
Copy link
Contributor

@francois-ferrandis francois-ferrandis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magnifique ! 😍 🚀

Concernant la gestion de l’erreur côté front, on est assez ok avec Mehdi et Teo pour redirigé vers la page de connexion en cas de 401. Je suis moyen convaincu par le window.reload donc je l’ai sorti de la PR et je vais faire une proposition dans une autre PR. Il était juste là à titre d’exemple pour montrer que ça fonctionne.

C'est très raisonnable, j'ai hâte de voir la suite ! 👍


context "when agent is not login" do
it "returns unauthorized" do
get :index, params: { agent_id: 1, organisation_id: 1, start: "2019-08-12", end: "2019-08-19", format: :json }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

J'apprécie beaucoup que cette spec ne reprenne pas tous les let de l'enfer de celle d'au-dessus, bravo ! 👏

@AntoineGirard AntoineGirard force-pushed the feat/refacto-agenda-internal-api branch 2 times, most recently from 4320302 to 50f9a4f Compare November 26, 2024 14:24
@AntoineGirard AntoineGirard force-pushed the feat/refacto-agenda-internal-api branch from 50f9a4f to 2340c2a Compare November 27, 2024 09:49
@AntoineGirard AntoineGirard merged commit ce86132 into production Nov 27, 2024
16 checks passed
@AntoineGirard AntoineGirard deleted the feat/refacto-agenda-internal-api branch November 27, 2024 10:00
@francois-ferrandis
Copy link
Contributor

Woooops on a pas pensé à la "migration", là on vient de déployer un changement de route et donc tout le monde se tape des alert, non ? 😬

@AntoineGirard
Copy link
Member Author

AntoineGirard commented Nov 27, 2024

@francois-ferrandis, je n’avais pas vu ton message 😬
Effectivement, on aurait dû laisser les anciens points le temps que tout le monde recharge le front…
Un peu tard pour le coup, mais pour la prochaine fois ça serait bien de gérer ça oui…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

4 participants