2

I am designing a REST API that has to deal with users and two video uploads associated to each user. So far, I've come up with two different approaches of modeling this:

  1. Video as part of a user resource.
  2. Video as a subresource of a user resource.

Each approach has its (philosophical) advantages and problems: To explain in more detail, the model for my users resource kinda looks like this:

{
   "id": Number, // user id
   "cat_video_upload_date": Date, // initially unset, date of cat video upload
   "dog_video_upload_date": Date, // initially unset, date of dog video upload
}

Going for approach 1, I have

  • PATCH /users/{id} to update a user resource with a video via multipart upload
  • GET /users/{id}/{file} where file can be "cat.mp4" or "dog.mp4"

While the PATCH looks fine wrt REST, I feel that GET /users/{id}/{file} is "wrong" when it comes to sticking with the true nature of a RESTful API. It should probably rather be GET /users/{id}#{file}, treating the file as a secondary resource as highlighed by this answer, but this won't be handled by the server as pointed by by this SO post.

Going for approach 2, I have

  • POST /users/{id}/videos to update the videos subresource of a user resource with a video via multipart upload
  • GET /users/{id}/videos/{file} where file can be "cat.mp4" or "dog.mp4"

This looks all nice and RESTy, but I'm unsure whether it's OK to to have the POST /users/{id}/videos set cat_video_upload_date and/or dog_video_upload_date in the user resource, i.e. have a POST to a subresource implicitly trigger an update to the parent resource.

To sum this up: While both "just work", which approach of the two is The Right Way in terms of sticking to the true REST philosophy? Is there maybe another approach I haven't thought of?

3 Answers 3

2

How would you do it as a web site?

Most of the time, it would look like three primary resources - the user web page, and separate web images. So the identifier design might look like

/users/1
/users/1/videos/cat.mp4
/users/1/videos/dog.mp4

If you wanted the server to change its representation of the resource to match yours, you would sent a PUT request; the request target would be the URI of the resource you wanted to change, the request body would be a copy of your representation.

But we didn't normally use PUT very often on the web; instead, the more common choice would be to use POST: one or more web forms that allow the user to describe a supported change, the the form meta data ensuring that the browser uses the correct request-target.

Notice the important advantage that we got from hypermedia: the client and the browser don't need to guess what the request-target should be, because the answer to that question is described by the representation of the form.

Thus, in practice when designing the origin server you could choose what request-target you wanted to use for each form

POST /users/1
POST /users/1/videos/cat.mp4
POST /users/1/cat-form-handler
POST /cat-form-handler
POST /0ed11b64-d4e8-4e86-813d-2988e0ca1279

Those are all fine - different trade offs.

Could you use PATCH instead of POST? Yes, assuming your server can interpret one or more patch document media types for the resource. For an HTML web page, that would probably be some sort of text diff format. For a JSON representation, you might instead use a JSON Patch or JSON Merge Patch.


Now, could you instead use a resource model with one primary resource that has two secondary resources embedded within it?

Yes... though I'm not sure you would like it very much.

As before, you can absolutely do edits with POST, and the request target can be anything you want because hypermedia.

An embedded image in a web page is often a data url with an encoded representation of the image (eg: base64) that means your binary data is just text. So in theory you can just PUT new representations easily enough, or PATCH the text.


PATCH /users/{id} to update a user resource with a video via multipart upload

Not an answer that I like at all - it seems to be hijacking PATCH to no real benefit.

The exact same body with POST is fine, because POST has looser semantic constraints than PATCH does.

POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.” -- Fielding, 2009

HTTP Request methods are used to identify the semantics of the request, NOT the implementation on the server. It's part of the "uniform interface" constraint.

1

I will go with approach 2. It looks cleaner.

When designing an API, looking it from the consumer perspective helps. The date setting logic is internal to the implementation. That said, the model looks odd to me. Maybe you need to keep videos in the model with file and date.

0

Both seem a little bit "hacky" to me.

I'd model it a bit different.

  • POST /users/{user-id}/videos creates a new video resource for the user with the file as a child resource and returns a new unique id
  • GET /users/{user-id}/videos/{video-id} returns the metadata for the file - so sth. like {"fileName": "cat.mp4", "createdAt": 1632824756387, "fileSizeMB": 200, "mimeType": "video/mp4"}
  • GET /users/{user-id}/videos/{video-id}/file returns the actual file

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.