views:

437

answers:

5

I'm trying to create a REST web service that exposes the following Django model:

class Person(models.Model):
    uid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=40)
    latitude = models.CharField(max_length=20)
    longitude = models.CharField(max_length=20)
    speed = models.CharField(max_length=10)
    date = models.DateTimeField(default=datetime.datetime.now)

    def __unicode__(self):
        return self.name

Here's how I thought about it so far:

Get all Persons
URL: http://localhost/api/persons/
Method: GET
Querystring:

  • startlat=
  • endlat=
  • startlng=
  • endlng=

Used for getting the Persons that are within the specified coordinate range.

  • page=

Used for getting the specified page of the response (if the response contains multiple pages).

Returns:

  • 200 OK & JSON
  • 404 Not Found

Example:
Request:

GET http://localhost/api/persons/?startlat=10&endlat=15&startlng=30&endlng=60

Response:

{
  "persons":
  [
     { "href": "1" },
     { "href": "2" },
     { "href": "3" },
     ...
     { "href": "100" }
  ],
  "next": "http://localhost/api/persons/?startlat=10&endlat=15&startlng=30&endlng=60&page=2"
}


Get info on a specified Person
URL: http://localhost/api/persons/[id]
Method: GET
Returns:

  • 200 OK & JSON
  • 404 Not Found

Example:
Request:

http://localhost/api/persons/5/

Response:

{
  "uid": "5",
  "name": "John Smith",
  "coordinates": {
                   "latitude":"14.43432",
                   "longitude":"56.4322"
                 },
  "speed": "12.6",
  "updated": "July 17, 2009, 8:46 a.m."
}



How correct is my attempt so far? Any suggestions are highly appreciated.

+1  A: 

Seems REST-cool. Even i worked on same kind of thing, few days earlier.

The only change, i would love to do in it, is the direct link to the person details. And also some details (like name here) to identify the person, and aid me in decision to navigate further. Like...

{
  "persons":
  [
     { "name": "John Smith", "href": "http://localhost/api/persons/1/" },
     { "name": "Mark Henry", "href": "http://localhost/api/persons/2/" },
     { "name": "Bruce Wayne", "href": "http://localhost/api/persons/3/" },
     ...
     { "name": "Karl Lewis", "href": "http://localhost/api/persons/100/" }
  ],
  "next": "http://localhost/api/persons/?startlat=10&endlat=15&startlng=30&endlng=60&page=2"
}

This way, i am giving everything, to present data as,

Next Page

simplyharsh
Actually, unless you include the actual URIs in the response, it's not RESTful at all. +1
Wahnfrieden
+2  A: 
{ "href": "1" },

1 is hardly a valid URL. You should use full URLs. Google for HATEOAS.

Also, remember to send a relevant Content-Type header. You may want to make up your own mime-type to describe the format. This gives you the option to later change the content-type (Eg. change the format after publishing). See Versioning REST Web Services

troelskn
Thanks! While I was designing the service I read an article (http://bitworking.org/news/restful_json/) which inspired me to use relative URLs. Why do you think that using relative URLs is not such a good ideea?
Robert Smith
While relative URLs are probably ok in theory, they present a problem in practise. It's very likely that a client will hardcode the URL construction, rather than actually resolve the URL relative. This makes your api brittle. On the flip side, what is it really that you gain by making URLs relative? If it's performance, then consider using compression, which will remove the redundancy quite efficiently.On a side note - Remember to make your resources cacheable (Send Etags and expires-headers)
troelskn
I use relative urls in xml-based media types and they work ok. Be careful with trailing slashes though because a relative url "1" is different if the base url is "http://localhost/api/persons" or "http://localhost/api/persons/" I use an xml:base attribute to avoid the confusion. To partially answer troelskn's question. I find relative url's simpler to generate on the server side.
Darrel Miller
@darrel I can see how xml-based media is probably relatively safe for relative urls (after all browsers support them), but it's still on the client. This is probably a border line issue and as such I think the safest is to be conservative about it. In this case I didn't immediately recognise it as a relative url. That may just be me, but I suspect that other people might make the same mistake. REST is about avoiding custom protocols and sticking with standards (in as far as they are there) and I think this is on the wrong side of the fence. Well, that's my opinion anyway.
troelskn
+1  A: 

I think query parameters could be simpler and clearer. This would make the URI more readable and would allow more flexibility for future extensions:

GET http://localhost/api/persons/?latitude=10:15&longitude=30:60

You may want to enable these in the future:

GET http://localhost/api/persons/?latitude=10&longitude=60&within=5km
Vincent Robert
A: 

It's ok to provide shorthand URIs in your JSON responses if you provide some templating system. Like giving a base URI as something like http://whatever.com/persons/{id}/ and then providing IDs. Then with python you can just do a format call on the string. You don't ever want to make the programmer actually look at and understand the meaning of the URIs, which isn't necessary when you use templates.

Wahnfrieden
I just want to note that it's essential you provide this template as part of the response, not in your out-of-band API spec.
Wahnfrieden
A: 

You might want to take a look at pre-existing REST middleware. I know they saved me a lot of time. I'm using http://code.google.com/p/django-rest-interface/. And a snippet of the urls.py

json_achievement_resource = Collection(
    queryset = Achievement.objects.all(),
    permitted_methods = ('GET',),
    responder = JSONResponder(paginate_by = 10)
)

urlpatterns += patterns('',
    url(r'^api/ach(?:ievement)?/(.*?)/json$', json_achievement_resource),
)
Paul Tarjan