Django api - How to use DestroyAPIView and maintain RESTfulness - django

How would one use Django DestroyAPIView and DetailAPIView and still maintain generally accepted practices of RESTfulness?
If I understand REST correctly it should work as follow (only one example)
/api/game/222
then 1 view class(generics.DetailAPIView) or method, in Django would be created to handle the call
In a REST world, I believe we would use a generic API class to handle the
methods (get,...)
But if I wanted to use the class(generics.DestroyAPIView) to handle the calls to delete a game.
then I would have to use
/api/game/delete/222
to send the request to the correct view.
It seems to me this is not consistent with RESTFULness.
for the delete method of the HTTP should be used to send the delete request and use the same pattern matching /apt/game/222 to delete the game. It's redundant.
Question: Am I missing something?
In summary
option 1:
/api/game/delete/222 (DestroyAPIView)
/api/game/detail/222 (DetailAPIView)
option 2
/api/game/222 (RetrieveDestroyAPIView)
I guess either way works, and as long as it's clear and consistent as stated below. There is no "right" way.

I not sure 'RESTFULness' affect what you are asking here. It is perfectly fine to have different matching pattern as long as it make sense.
In the example given, usually we do not have /api/game/222 as a generics.ListCreateAPIView. This is because List return a list of all game, we do not pass a id in. Create is trying to create a new Game. You do not have id yet because it is not in database, therefore both of the matching pattern should usually be /api/game/ instead.
/api/game/222 - such pattern, we usually use for generics.RetrieveUpdateDestroyAPIView because with a given id in url, we can get the correct Game object to either retrieve, update or delete it.
Regarding the Restful API, the answers in this stack overflow question explain more about 'Restfulness'.

Related

Correct REST API URL format for related objects

I'm designing a REST API where, amongst others, there are two objects.
Journey
Report
For each Journey there are many Reports enroute, and each Report has exactly one associated Journey.
A user might create a Journey using the API as follows...
POST /journey/
Then retrieve the details...
GET /journey/1226/
The first question is, if a user wanted to post an Report to their Journey, which is the 'correct' URL structure that the API should impose? This seems intuitive to me...
POST /journey/1226/report/
...or is this the case...
POST /report/
...whereby in the latter, the Journey ID is passed in the request body somewhere?
The second question is, how might one go about implementing the first case in a tool such as the Django REST framework?
Thanks!
The URL/URI structure is almost completely irrelevant. It is nice to be able to read it, or easily change or even guess it, but that is it. There is no "requirement" official or unwritten how they should look like.
The point is however, that you supply the URIs to your clients in your responses. Each GET will get you a representation that contains links to the next "states" that your client can reach. This means the server has full control over URI structure, the client usually has to only know the "start" or "homepage" URI, and that's it.
Here is an article which discusses this question, has some good points: http://www.ben-morris.com/hackable-uris-may-look-nice-but-they-dont-have-much-to-do-with-rest-and-hateoas/
Pass for the second question :) I didn't use that particular framework.

What's the correct way to create a REST service that allows for different types of identifiers?

I need to create a RESTful webservice that allows for addressing entities by using different types of IDs. I will give you an example based on books (which is not what I need to process but I want to build a common understanding this way).
Books can be identifier by:
ISBN 13
ID
title
I can create a book by POSTing to /api/v1/books/The%20Bible. This book can then later be addressed by its ISBN /api/v1/books/12312312301 or ID /api/v1/books/A9471IZ1. If I implemented it this way I would need to analyze whatever identifier gets sent and convert it internally.
Is it 'legal' to add the type of identifier to the URL ? Like /api/v1/books/title/The%20Bible?
It seems that what you need is not simply retrieving resources, but searching for them by certain criteria (in your case, by ISBN, title or ID). In that case, rather than complicate your /books endpoint (which, ideally, should only returns books by ID), I'd create a separate /search function. You can then use it search for books by any field.
For example, you would have:
GET /search?title=bible
GET /search?isbn=12312312301
It can even be easily expanded to add more fields later on.
First: A RESTful URl should only contain nouns and not verbs. You can find a lot of best-practices online, as example: RESTful API Design: nouns are good, verbs are bad
One approach would be to detect the id/identifier in code.
The pattern would be, as you already mentioned:
GET /api/v1/books/{id}, like /api/v1/books/12312312301 or /api/v1/books/The%20Bible
Another approach, similar to this.lau_, would be with a query parameter. But I suggest to add the query parameter to the books URL (because only nouns, no verbs):
GET /api/v1/books?isbn=12312312301
The better solution? Not sure…
Because you are selecting “one book by id” (except title), rather than performing a query/search, I prefer the first approach (…/books should return “a collection of books” and .../books/{id} should return only one book).
But maybe someone has a better approach/idea?
Edit:
I suggest to avoid adding the identifier to the URL, it has “bad smell”. But is also a possible approach and I saw that a lot in other APIs. Let’s see if I can find some information on that, if its “ok” or should be avoided.
Edit 2:
See REST API DESIGN - Getting a resource through REST with different parameters but same url pattern and REST - supporting multiple possible identifiers

Is this a RESTful way to handle multiple verbs for a resource?

I am attempting to write a Restful API to control a CMS. There are Objects (e.g., An instance of an Article) and each object has multiple Drafts. To work on an object's Drafts, I built a URL like this:
/cms/objects/{objectId}/drafts/{draftId}
draftIds are not unique unless you provide an objectId.
Hopefully I haven't already messed up with this. But now I have multiple verbs I want to perform on each Draft. Here's a list of verbs:
CLONE, UNPUBLISH, PUBLISH, UNLOCK, LOCK
The way I approached this is to create an endpoint that has an operation query param. And here's an example of how you use it:
POST /cms/objects/3232/drafts/1?operation=CLONE
POST /cms/objects/3232/drafts/1?operation=LOCK
Is there a better way to do this? I'm actually upgrading an already existing API, and the way you used to do something like this is like so:
POST cms/objects/3232/duplicate-draft?source-draft-id=1
POST cms/objects/3232/lock?draft-id=1
I prefer my way, because in my eyes it's more consistent (though I am biased). Is there a better way to do this?
By the way, I am aware of this question that is very similar. The reason I'm creating this new one is that mine is laser focused on the "multiple verb" aspect and his isn't. His is more like, "how do I do multiple verbs and can you teach me lots of other stuff about Restful APIs, too?"
Also, I feel that the accepted answer on that question does not sufficiently address this (see his point 2). For example, my Drafts, do not have a lock=true in their body so I can't easily map the advice from his Change Password section. My Drafts have two fields to represent if the Draft is locked: The user name of the locker and the user id of the locker. It would be inconvenient to have the client pass these both in so my intent above is to abstract that work away from the client.

RESTful API and Foreign key handling for POSTs and PUTs

I'm helping develop a new API for an existing database.
I'm using Python 2.7.3, Django 1.5 and the django-rest-framework 2.2.4 with PostgreSQL 9.1
I need/want good documentation for the API, but I'm shorthanded and I hate writing/maintaining documentation (one of my many flaws).
I need to allow consumers of the API to add new "POS" (points of sale) locations. In the Postgres database, there is a foreign key from pos to pos_location_type. So, here is a simplified table structure.
pos_location_type(
id serial,
description text not null
);
pos(
id serial,
pos_name text not null,
pos_location_type_id int not null references pos_location_type(id)
);
So, to allow them to POST a new pos, they will need to give me a "pos_name" an a valid pos_location_type. So, I've been reading about this stuff all weekend. Lots of debates out there.
How is my API consumers going to know what a pos_location_type is? Or what value to pass here?
It seems like I need to tell them where to get a valid list of pos_locations. Something like:
GET /pos_location/
As a quick note, examples of pos_location_type descriptions might be: ('school', 'park', 'office').
I really like the "Browseability" of of the Django REST Framework, but, it doesn't seem to address this type of thing, and I actually had a very nice chat on IRC with Tom Christie earlier today, and he didn't really have an answer on what to do here (or maybe I never made my question clear).
I've looked at Swagger, and that's a very cool/interesting project, but take a look at their "pet" resource on their demo here. Notice it is pretty similar to what I need to do. To add a new pet, you need to pass a category, which they define as class Category(id: long, name: string). How is the consumer suppose to know what to pass here? What's a valid id? or name?
In Django rest framework, I can define/override what is returned in the OPTION call. I guess I could come up with my own little "system" here and return some information like:
pos-location-url: '/pos_location/'
in the generic form, it would be: {resource}-url: '/path/to/resource_list'
and that would sort of work for the documentation side, but I'm not sure if that's really a nice solution programmatically. What if I change the resources location. That would mean that my consumers would need to programmatically make and OPTIONS call for the resource to figure out all of the relations. Maybe not a bad thing, but feels like a little weird.
So, how do people handle this kind of thing?
Final notes: I get the fact that I don't really want a "leaking" abstaction here and have my database peaking thru the API layer, but the fact remains that there is a foreign_key constraint on this existing database and any insert that doesn't have a valid pos_location_type_id is raising an error.
Also, I'm not trying to open up the URI vs. ID debate. Whether the user has to use the pos_location_type_id int value or a URI doesn't matter for this discussion. In either case, they have no idea what to send me.
I've worked with this kind of stuff in the past. I think there is two ways of approaching this problem, the first you already said it, allow an endpoint for users of the API to know what is the id-like value of the pos_location_type. Many API's do this because a person developing from your API is gonna have to read your documentation and will know where to get the pos_location_type values from. End-users should not worry about this, because they will have an interface showing probably a dropdown list of text values.
On the other hand, the way I've also worked this, not very RESTful-like. Let's suppose you have a location in New York, and the POST could be something like:
POST /pos/new_york/
You can handle /pos/(location_name)/ by normalizing the text, then just search on the database for the value or some similarity, if place does not exist then you just create a new one. That in case users can add new places, if not, then the user would have to know what fixed places exist, which again is the first situation we are in.
that way you can avoid pos_location_type in the request data, you could programatically map it to a valid ID.

REST services - exposing non-data "actions"

I understand how to use REST for doing general entity interactions - using urls names to map to entities and the HTTP verbs to map to actions on those entities. But what is the generally accepted way of looking at "actions" more like RPC?
For example, let's say I want to send a command for the device to reset? There's no real "entity" here or do I do something like POST to http://mydevice/device/reset?
/device/reset or /system/reset are ok.
The REST "design pattern" does encourage you to NOT use any verbs.. You could do:
POST http://mydevice/system/state
<stateType>RESET</stateType>
Related information:
How to create REST URL’s without verbs?
Threads tagged with restful-url
I don't think that's the case to use POST. The "RESET action" is a idempotent action (if you call it n times you will always get the same result), so IMHO you should use a PUT call instead POST (as POST is not idempotent).
Also, as you are Putting a resource, you can use
PUT http://system
<device>
<status>RESET</status>
</device>
or
PUT http://system/status/reset
But I think the first one is "more restful", since you are putting a resource, while the second one you just use the URL.
I usually name the entity "system" or something like that. So you do "/system/reset". You've chosen device so that works too.
But yea, I usually consider these types of actions to be updates, which would use the POST method. So I think you are right to POST to /device/reset