Nous développons un serveur avec l'API REST, qui accepte et répond avec JSON. Le problème est, si vous devez télécharger des images du client au serveur.
Remarque: et je parle aussi d'un cas d'utilisation où l'entité (utilisateur) peut avoir plusieurs fichiers (carPhoto, licensePhoto) et également avoir d'autres propriétés (nom, email ...), mais lorsque vous créez un nouvel utilisateur, vous ne N'envoyez pas ces images, elles sont ajoutées après le processus d'inscription.
Les solutions dont j'ai connaissance, mais chacune d'elles présente des défauts
1. Utilisez multipart / form-data au lieu de JSON
bon : les requêtes POST et PUT sont aussi RESTful que possible, elles peuvent contenir des entrées de texte avec un fichier.
inconvénients : Ce n'est plus JSON, ce qui est beaucoup plus facile à tester, déboguer, etc. par rapport à multipart / form-data
2. Autoriser la mise à jour de fichiers séparés
La requête POST pour créer un nouvel utilisateur ne permet pas d'ajouter des images (ce qui est correct dans notre cas d'utilisation comme je l'ai dit au début), le téléchargement des images se fait par requête PUT en multipart / form-data vers par exemple / users / 4 / carPhoto
bon : tout (sauf le fichier qui se télécharge) reste en JSON, il est facile de tester et de déboguer (vous pouvez enregistrer des requêtes JSON complètes sans avoir peur de leur longueur)
inconvénients : Ce n'est pas intuitif, vous ne pouvez pas POST ou PUT toutes les variables de l'entité à la fois et cette adresse /users/4/carPhoto
peut également être considérée comme une collection (le cas d'utilisation standard de l'API REST ressemble à ceci /users/4/shipments
). Habituellement, vous ne pouvez pas (et ne voulez pas) GET / PUT chaque variable d'entité, par exemple users / 4 / name. Vous pouvez obtenir le nom avec GET et le modifier avec PUT à users / 4. S'il y a quelque chose après l'identifiant, il s'agit généralement d'une autre collection, comme users / 4 / reviews
3. Utilisez Base64
Envoyez-le au format JSON mais encodez les fichiers avec Base64.
bon : Identique à la première solution, c'est le service le plus REST possible.
inconvénients : Une fois de plus, les tests et le débogage sont bien pires (le corps peut avoir des mégaoctets de données), il y a augmentation de la taille et aussi du temps de traitement à la fois - client et serveur
Je voudrais vraiment utiliser la solution no. 2, mais il a ses inconvénients ... N'importe qui peut me donner un meilleur aperçu de la solution "quelle est la meilleure"?
Mon objectif est d'avoir des services RESTful avec autant de standards inclus que possible, tout en souhaitant que les choses restent aussi simples que possible.
Réponses:
OP ici (je réponds à cette question au bout de deux ans, le post de Daniel Cerecedo n'était pas mal à la fois, mais les services web se développent très vite)
Après trois ans de développement logiciel à plein temps (en mettant également l'accent sur l'architecture logicielle, la gestion de projet et l'architecture de microservices), je choisis définitivement la deuxième méthode (mais avec un point final général) comme la meilleure.
Si vous avez un point final spécial pour les images, cela vous donne beaucoup plus de pouvoir sur la gestion de ces images.
Nous avons la même API REST (Node.js) pour les applications mobiles (iOS / Android) et frontend (utilisant React). Nous sommes en 2017, vous ne voulez donc pas stocker les images localement, vous voulez les télécharger sur un stockage cloud (Google cloud, s3, cloudinary, ...), donc vous voulez une manipulation générale sur elles.
Notre flux typique est que dès que vous sélectionnez une image, elle commence à télécharger en arrière-plan (généralement POST sur / images endpoint), vous renvoyant l'ID après le téléchargement. C'est vraiment convivial, car l'utilisateur choisit une image et passe généralement avec d'autres champs (c'est-à-dire adresse, nom, ...), donc quand il clique sur le bouton «envoyer», l'image est généralement déjà téléchargée. Il n'attend pas et regarde l'écran disant "uploading ...".
Il en va de même pour obtenir des images. Surtout grâce aux téléphones mobiles et aux données mobiles limitées, vous ne voulez pas envoyer d'images originales, vous voulez envoyer des images redimensionnées, afin qu'elles ne prennent pas autant de bande passante (et pour rendre vos applications mobiles plus rapides, vous ne voulez souvent pas pour le redimensionner, vous voulez que l'image s'intègre parfaitement dans votre vue). Pour cette raison, les bonnes applications utilisent quelque chose comme cloudinary (ou nous avons notre propre serveur d'images pour le redimensionnement).
De plus, si les données ne sont pas privées, vous renvoyez à l'application / frontend juste une URL et il les télécharge directement à partir du stockage en nuage, ce qui représente une énorme économie de bande passante et de temps de traitement pour votre serveur. Dans nos plus grandes applications, il y a beaucoup de téraoctets téléchargés chaque mois, vous ne voulez pas gérer cela directement sur chacun de votre serveur d'API REST, qui est axé sur le fonctionnement CRUD. Vous souhaitez gérer cela à un seul endroit (notre serveur d'images, qui dispose de la mise en cache, etc.) ou laisser les services cloud gérer tout cela.
Inconvénients: Le seul «inconvénient» auquel vous devriez penser est «images non attribuées». L'utilisateur sélectionne des images et continue à remplir d'autres champs, mais ensuite il dit "non" et éteint l'application ou l'onglet, mais en attendant, vous avez téléchargé l'image avec succès. Cela signifie que vous avez téléchargé une image qui n'est attribuée nulle part.
Il existe plusieurs façons de gérer cela. Le plus simple est "Je m'en fiche", qui est pertinent, si cela ne se produit pas très souvent ou si vous avez même le désir de stocker toutes les images que les utilisateurs vous envoient (pour une raison quelconque) et que vous n'en voulez pas effacement.
Un autre est facile aussi - vous avez CRON et c'est-à-dire chaque semaine et vous supprimez toutes les images non attribuées de plus d'une semaine.
la source
Il y a plusieurs décisions à prendre :
Le premier sur le chemin des ressources :
Modélisez l'image en tant que ressource à elle seule:
Nested in user (/ user /: id / image): la relation entre l'utilisateur et l'image se fait implicitement
Dans le chemin racine (/ image):
Le client est tenu responsable de l'établissement de la relation entre l'image et l'utilisateur, ou;
Si un contexte de sécurité est fourni avec la requête POST utilisée pour créer une image, le serveur peut implicitement établir une relation entre l'utilisateur authentifié et l'image.
Incorporer l'image dans le cadre de l'utilisateur
La deuxième décision concerne la manière de représenter la ressource image :
Ce serait ma piste de décision:
Vient ensuite la question: y a-t-il un impact sur les performances à propos du choix de base64 vs multipart? . On pourrait penser que l'échange de données au format multipart devrait être plus efficace. Mais cet article montre à quel point les deux représentations diffèrent peu en termes de taille.
Mon choix Base64:
la source
Votre deuxième solution est probablement la plus correcte. Vous devez utiliser les spécifications HTTP et les types MIME comme prévu et télécharger le fichier via
multipart/form-data
. En ce qui concerne la gestion des relations, j'utiliserais ce processus (en gardant à l'esprit que je n'en sais rien sur vos hypothèses ou la conception du système):POST
pour/users
créer l'entité utilisateur.POST
l'image vers/images
, en veillant à renvoyer un en-Location
tête où l'image peut être récupérée selon les spécifications HTTP.PATCH
à/users/carPhoto
et attribuez-lui l'identifiant de la photo donnée dans l'en-Location
tête de l'étape 2.la source
Il n'y a pas de solution simple. Chaque façon a ses avantages et ses inconvénients. Mais la manière canonique est en utilisant la première option:
multipart/form-data
. Comme le dit le guide de recommandation W3Nous n'envoyons pas de formulaires, vraiment, mais le principe implicite s'applique toujours. L'utilisation de base64 comme représentation binaire est incorrecte car vous utilisez le mauvais outil pour atteindre votre objectif, en revanche, la deuxième option oblige vos clients API à faire plus de travail afin de consommer votre service API. Vous devez faire le travail acharné côté serveur afin de fournir une API facile à utiliser. La première option n'est pas facile à déboguer, mais quand vous le faites, elle ne change probablement jamais.
En utilisant,
multipart/form-data
vous êtes fidèle à la philosophie REST / http. Vous pouvez voir une réponse à une question similaire ici .Une autre option si vous mélangez les alternatives, vous pouvez utiliser multipart / form-data mais au lieu d'envoyer chaque valeur séparément, vous pouvez envoyer une valeur nommée payload avec la charge utile json à l'intérieur. (J'ai essayé cette approche en utilisant ASP.NET WebAPI 2 et fonctionne bien).
la source