ZEP-23 : Elaboration de l'API des MPs

a marqué ce sujet comme résolu.

Personne n'est en mesure de retirer les membres d'un MP hormis les utilisateurs eux-même. Donc, tu renseignes que les utilisateurs que tu veux rajouter. Si tu veux en rajouter plusieurs, tu dois spécifier le paramètre participants plusieurs fois.

Edit :

Le problème est toujours qu'avec l'identifiant http ça bloque l'identification oauth et donc limite la portée des tests.

Comment ça ?

+0 -0

Bin on ne peut pas se connecter avec OAuth quand le server est protégé par une identification http (ou alors je veux bien que quelqu'un m'explique comment) car les deux identifications utilisent un parametre commun de la requete HTTP.

tu dois spécifier le paramètre participants plusieurs fois

Attends je comprends pas : tu renseignes plusieurs fois le même noeud en JSON ? Tu fais N requêtes ? C'est un queryParam multi-valué ?

+0 -0

Je vais prendre le problème autrement, comment est-ce que vous aurez fais la requête pour ajouter 2 participants à un MP ?

Andr0

Comme je l'ai dit ci-dessus, j'aurai séparé (une url dédiée) la notion d'ajout d'un participant à un MP. Il s'agit tout de même d'ajouter une ressource à une autre (et ça ne pourra faire que tu bien à l'API des notifications derrière).

PUT /api/mp/{mpId}/participants avec dans le corps de la requête une liste de participants (éventuellement avec un seul élément) et un paramètre (dans l'URL) pour indiquer si on ajoute simplement ou si on veut remplacer la liste (pour les staff). Valeur par défaut == on ajoute.

exemple pour un staff : PUT /api/mp/{mpId}/participants?replace=true

C'est pas forcément la meilleure solution, tu connais le projet bien mieux que moi. Mais en fait je suis incapable de le dire car je ne comprends pas la solution que tu as mise en place (et sa description dans la doc swagger). C'est ce que j'essayais de dire dans mon message précédent.

Qu'est-ce-que (Swagger et toi) vous appelez un paramètre dans ce contexte ? J'arrive pas à comprendre.

Un paramètre pour moi c'est un query parameter et pour qu'il prenne plusieurs valeurs ça pourrait (mais j'en sais rien…) être un query parameter multi-valué. On peut aussi passer une liste séparée par des virgules par exemple dans l'URL.

Mais si j'essaie de comprendre Swagger j'ai un doute, et j'ai l'impression que ça pourrait être un paramètre à l'intérieur du corps de la requête (charge utile, payload : le JSON quoi) et je crois pas que ça fonctionne en JSON ça : http://www.ietf.org/rfc/rfc4627.txt?number=4627 (section 2.2) c'est la dernière valeur qui sera prise en compte. En XML on écrirait :

1
2
<participant>123</participant>
<participant>456</participant>

En JSON :

1
"participants" : [123,456]

Du coup je suis complètement paumé, et c'est juste un problème de nomenclature. Peut-être que si tu donnais un exemple de requête pour ajouter 2 participants à un MP, ça m'aiderait :)

Merci !

+2 -0

Alors, déjà, il faut savoir que personne (pas même le staff) ne peut retirer des participants à un MP. Ce n'est juste pas possible. La seule manière pour retirer une personne d'un MP, c'est que cette personne se retire d'elle-même en quittant la conversation privée (d'où les URLs DELETE pour quitter une conversation).

Quelle est la conséquence de ce fait ? Il n'y a pas moyen de remplacer des participants quand vous tentez d'éditer une conversation privée, vous ne pouvez que ajouter un participant (en renseignant son identifiant), comme c'est le cas sur le site actuellement.

Ceci étant clarifié (je l'espère), problème suivant : Javier tu as mis le doigt dessus. participants est un paramètre form multi-valué. C'est-à-dire que vous pouvez renseigner 0 à n fois le paramètre. 0 pour n'ajouter aucun participant quand vous éditez une conversation. n pour ajouter n participants à la conversation.

La requête POST sera donc comme ceci :

URL : /api/mps/{pk}/

Méthode : PUT

Paramètres :

  • participants du type form
  • participants du type form (je le renseigne 2 fois parce que je veux ajouter 2 participants)
  • … (les autres)
+0 -0

Je crois que la question est plutôt « comment voyez-vous l'ajout de plusieurs participants d'un coup par opposition à l'ajout d'un seul nouveau dans votre système avec une URL dédiée ? ». ;)

Dominus Carnufex

Un truc comme ça (pour créer un MP avec plusieurs participants d'un coup) : curl -X POST http://http://zestedesavoir.com/api/mps/{pk}/ -d @new-mp.json avec new-mp.json equivalent à un truc comme ça :

1
2
3
4
5
6
7
{
"title" : "la mère à boire",
"subtitle" : "la bouteille à la mère",
"message" : "L'eau, la vie et le destin",
"author" : "firm1",
"participants" : ["Andr0", "Dominus Carnufex"]
}

Maintenant, le PUT sur cette URL ne devrait pas permettre de modifier les participants. le PUT sur /api/mps/{pk}/ devrait uniquement permettre de modifier les propriétés (title, subtitle, message, author) du MP. C'est là qu'on devrait avoir une deuxième URL dédiée à l'ajout d'un participant à une conversation.

OK pour le paramètre form multi-valué.

Mais du coup pour les différents content-types on fait quoi (ça donne quoi) ?

On gère que le application/x-www-form-urlencoded ?

Parce que je vois pas comment faire l'équivalent d'un param multi-valué en JSON. Que propose DRF ? Des tableaux, tout simplement ?

+0 -0

Ok, je crois comprendre le problème de votre côté. Alors il faut en comprendre un technique. Il y a un petit moment, cette ZEP a été mise en pause parce que j'étais coincé sur ce problème justement. C'était la première fois que je rencontrais une relation many to many dans le modèle dans le cadre de l'API. Je voulais trouver la solution la plus adéquate en gardant tous les concepts génériques de DRF.

J'ai essayé des tonnes de truc et la seule chose qui fonctionne, c'est le paramètre form multi-valué en renseignant les identifiants des participants (et non pas leurs username comme je l'aurais voulu). Donc oui, j'aurais aussi aimé fournir une liste de participants par leurs pseudos dans un seul champ, mais impossible si je voulais garder le "match" automatique avec le modèle et Serializer de DRF. Voilà le pourquoi de cette solution.

Parce que je vois pas comment faire l'équivalent d'un param multi-valué en JSON. Que propose DRF ? Des tableaux, tout simplement ?

Je t'avoue ne pas pouvoir te répondre. Je ne me suis pas renseigné à ce sujet.

Maintenant, le PUT sur cette URL ne devrait pas permettre de modifier les participants. le PUT sur /api/mps/{pk}/ devrait uniquement permettre de modifier les propriétés (title, subtitle, message, author) du MP. C'est là qu'on devrait avoir une deuxième URL dédiée à l'ajout d'un participant à une conversation.

Je me contente de suivre la spec sur laquelle nous nous sommes tous mis d'accord et je déteste changer la spec en cours de route. Cependant, à l'époque il était pas possible sur le site de changer les informations d'une conversation privée (titre et sous-titre) et je peux comprendre que la spec convenait puisqu'il n'y avait que les participants.

Donc, ce que nous pourrions faire c'est une nouvelle URL qui se contente d'ajouter des participants mais qui ne bénéficie pas de tout le côté générique de DRF. Je fais les choses manuellement en ajoutant tous les utilisateurs renseignés dans un champs du type String, free food pour l'utilisateur et si c'est pas formaté comme je le veux : code d'erreur 400.

Cela règle donc le problème de Javier puisqu'il sera possible d'utiliser l'URL en JSON et le problème général que vous soulevez.

Bah le truc pour les clients c'est que manipuler une API inconsistante dans les Content-Type (parfois des wwww-form-urlencoded et parfois du JSON) c'est vraiment méga chiant.

Ca m'est arrivé et tu t'arraches les cheveux, clairement. Et surtout, en tant que client API, t'en n'as strictement rien à faire des contraintes techniques du serveur (que tu ne comprends pas dans 90% des cas - c'est le cas ici pour moi par exemple). Donc j'imagine bien que c'est compliqué et tout et que sinon tu l'aurais fait bien entendu, mais en me mettant à la place d'un client, clairement le form-urlencoded c'est pas cool à devoir gérer :(

+2 -0

C'est pour ça que je ne voulais pas donner les raisons techniques mais vous m'avez forcé la main ! ^^

Ceci dit, concernant ton problème, je suis bien loin d'être un expert dans le domaine mais n'est-ce pas normal ? Je ne sais pas mais quand j'ai affaire à une API en POST ou PUT, je m'attendais à devoir le faire en formulaire.

Oula non, c'est pas normal.

Je prends souvent l'exemple de l'API de GitHub que je trouve très bien designée :

https://developer.github.com/v3/pulls/#create-a-pull-request

Tu passes pas par un formulaire pour faire du POST. En fait t'es en train de foutre en l'air le concept de REST là. En règle générale un client choisit un content-type et attend de l'API que toutes les ressources soient consistantes. Tout simplement parce que c'est pénible de jongler avec différents content-type et surtout ça demande au client d'avoir une connaissance avancée de l'API (attends mais oué cette URL là elle marche pas en JSON, celle-là oui, …).

Le but du jeu des frameworks côté serveur (toi qui connaît un peu Java, va voir RESTEasy par exemple) c'est de fournir une abstraction là-dessus.

La négociation du meilleur content-type se fait "par magie" "sous le capot" entre le client et le serveur, toi tu te contentes de lire ou retourner des données (en l'occurrence des Map, des tableaux ou des objets Java), sans avoir à te soucier de comment l'utilisateur va les recevoir. C'est pour cela que je suis un peu surpris que DRF ne soit pas capable de gérer ça (je pense que si en fait).

(je suis moi-même en train de développer un tel framework, c'est le genre de considérations dont je m'occupe à la place de l'utilisateur).

Y'a un cas qui va faire exception, c'est l'upload de fichier. Ou clairement, on n'a pas trop envie d'encoder l'ensemble du fichier en base64 avant de l'envoyer dans une requête avec une charge utile gigantesque (et donc perdre le chunked-encoding par exemple).

Dans ce cas-là, soit on fait une API d'upload dédiée (qui ne reçoit que le fichier, à l'aide d'une connexion chunked) et on gère les métadata à part, soit on passe par un formulaire multipart qui contient le fichier comme s'il était uploadé de façon "non REST" (non API quoi, avec un formulaire html) et un noeud qui lui, sera serializé en JSON, xml, … et contient les métadata.

Mais en dehors de ce genre de cas tordus, clairement on évite de mixer les content-type entre GET et POST et PUT, etc. Histoire que le client n'ait pas 50 types de données différents à gérer.

+6 -0

J'adore tes interventions Javier. ^^

Je comprends un peu mieux les choses. Du coup, j'ai fais un petit test pour voir si c'était possible puisque, je l'avoue sans trop comprendre, j'avais fais le nécessaire pour que ça soit possible. Donc, faire ce genre de requête :

1
curl -i -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer Token" http://localhost:8000/api/mps/2/ -d @edit-mp.json

Traite correctement la requête :

1
2
3
4
5
6
7
8
HTTP/1.0 200 OK
Date: Fri, 15 May 2015 13:41:57 GMT
Server: WSGIServer/0.1 Python/2.7.9
Vary: Accept
Content-Type: application/json
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS

{"id":2,"title":"la mère à boire","subtitle":"la bouteille à la mère","participants":[2,3]}

La bonne nouvelle : C'est que l'API permet de gérer ce Content-Type (et devrait l'être pour l'XML aussi) même pour les méthodes POST et PUT.

La mauvaise, c'est qu'effectivement, ça ne supporte pas l'implémentation actuelle pour ajouter des participants.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte