For this exercise, you will give your contact manager from homework #9/10 a REST API.
Create a
hw11
directory in your repository with a copy of your app from homework #9. You will be adding functionality to your previous app.-
Our application this week will have no authenitcation or authorization of any kind. We will allow anyone to see/edit any information. Obviously we could add in some appropriate authorization, but that's not the point.
I have created an example implementation of this app where you can see the total lack of authentication (and other features as described below; again, the database will be reset hourly). Also see the section below “Non-Requirements” for ways you don't have to make your life harder.
-
Your application should already be able to display information about a particular person at a unique URL for that “record”. For example, my app displays a record at URLs like: http://zju-webdev.cmpt.sfu.ca/contact-rest/1 . (Your URLs may be in a different format: that's fine, as long as there is some URL for each record.)
There should also be a URL for the “collection” of people in the system: your index/menu page. In my system, it is http://zju-webdev.cmpt.sfu.ca/contact-rest/ .
These URLs will become the identifiers for the data in the system. We will leave the regular “web site” part untouched: users should still be able to browse that info the same way they did before.
If you don't have URLs like this, update your system so you do. (If for some reason you want to change the URL layout from your app last week, you're free to do so.)
-
As the first step to our REST API, we will allow retrieval of a record in a more machine-readable format: JSON. We will use the same identifying URLs as above, but allow appropriate modifications to the request indicating the desired representation.
There are several ways the user of the API could indicate the representation they want. Some common ones:
- By examining the
Accept
header from the HTTP request. So, a request withAccept: application/json
would get a JSON response back, while a web browser's standard request (withtext/html
in theAccept
) would get the HTML response as before. (This one is the most pure REST.) - By adding a “file extension” to the URL. So, the HTML content at
/person/1
could be retrieved as JSON by requesting/person/1.json
. - By adding a query string indicating the format. For example, the HTML content at
/person/1
could be retrieved as JSON by requesting/person/1?fmt=json
.
Implement one of these so users can request a JSON representation of a record at its URL (or the URL slightly modified as above). [My example app implements all three methods, but you only need to do one.] The response should be a JSON object with the obvious fields in this format:
{ "first_name": "Some", "last_name": "Person", "email": "someperson@example.com", "phone": "604-555-1234", "notes": "Some notes about this person." }
You probably want to do this by creating a dictionary/map/object and passing it to your language's JSON library.
- By examining the
-
We also want our interface to allow editing records by passing JSON representations of data. To do this, we need to respond to HTTP PUT requests at the record's URL. That is, if the user PUTs data like the above JSON to the same identifying URL (like http://zju-webdev.cmpt.sfu.ca/contact-rest/1 in my system), the information for that person should be updated in the database.
Update your system so that it handles PUT requests with JSON data to a record's URL and updates the information appropriately. [See below for ways to generate these requests for testing, again, use your language's JSON library to parse the input.]
-
To add a new person to the collection, the usual REST way is to POST their information to the collection's URL (like http://zju-webdev.cmpt.sfu.ca/contact-rest/ in my system). We will use the same JSON respresentation of the data.
Update your system so that POSTing JSON data to the collection URL creates a new person in the database. [Again, see below for ways to generate these requests.]
-
Our last step is to allow deletion of records. This is usually done with the HTTP DELETE method and the record's URL (like http://zju-webdev.cmpt.sfu.ca/contact-rest/1).
Update your system so that it responds to DELETE requests at a record's URL by deleting that record from the database.
-
A summary of what your REST interface should be able to do:
REST operations we have implemented Operation HTTP Method URL Read record GET record URL (with some indication of desired representation) Update record PUT record URL (sending JSON representation) Create record POST collection URL (sending JSON representation) Delete record DELETE record URL That is, we have implemented an API for all of the CRUD operations using only HTTP methods, identifying URLs, and an appropriate representation of our data. The same URLs should still be usable within a browser to produce human-readable (HTML) versions of the information: an end-user will likely be totally unaware of this additional functionality.
Commit and push your work in the repository to the server.
Send an email to zju.webdev@gmail.com with the subject “Homework #11”. Include the path within your repository where we'll find your work. Be sure to include your student number in the body of the email so we find the right repository.
It may not be easier to use a REST framework: they are probably over-powered for the work here. It's probably easier to just introduce some logic like “if method=='PUT' then … else if method=='GET' then …
”.
Making Requests
To fully exercise your REST API, you need to make some HTTP requests that your browser won't do. Here are some curl
commands to (1) request JSON (for the Accept
header method from 3a above); (2) replace a person's info with data from a file data.json
; (3) create a new person with info from data.json
; and (4) delete a person's info:
curl -i -X GET -H "Accept: application/json" http://zju-webdev.cmpt.sfu.ca/contact-rest/1 curl -i -X PUT -H "Content-Type: application/json" -d @data.json http://zju-webdev.cmpt.sfu.ca/contact-rest/1 curl -i -X POST -H "Content-Type: application/json" -d @data.json http://zju-webdev.cmpt.sfu.ca/contact-rest/ curl -i -X DELETE http://zju-webdev.cmpt.sfu.ca/contact-rest/1
And the same operations using the Perl WWW library command:
lwp-request -eSs -m GET -H "Accept: application/json" http://zju-webdev.cmpt.sfu.ca/contact-rest/1 lwp-request -eSs -m PUT -c application/json http://zju-webdev.cmpt.sfu.ca/contact-rest/1 < data.json lwp-request -eSs -m POST -c application/json http://zju-webdev.cmpt.sfu.ca/contact-rest/ < data.json lwp-request -eSs -m DELETE http://zju-webdev.cmpt.sfu.ca/contact-rest/1
You might also find my data.json
file useful.
Non-Requirements
The following things are not required of the system you build for this exercise:
- Don't worry about error checking for badly-formed JSON, or other file types uploaded/requested.
- Editing the user's information in a web browser (i.e. an HTML form that you can submit to create/update info). I have left mine working in the example app, but you don't have to worry about it: just get the REST stuff working.
- I haven't specified what the HTTP response should be for the POST, PUT, DELETE operations. The “right” thing to do is probably to send a 201 Created or 302 Found respsonse, with a
Location
header to redirect to the record's URL (or the collection URL after a DELETE). That's what my system does, but you can do whatever is easiest. - JSON isn't really the best representation of this kind of data: vCard would make much more sense. But, using vCard would require a whole different set of parsing libraries, which are much less common. JSON is just easier.
- Other REST operations we could have done: PUT to the collection (to replace all records); GET the collection (to get a JSON array of all records); DELETE the collection (to remove all records); POST to the record to add sub-data (whatever that might be). I have implemented the collection GET in my system.
- Anything else I didn't explicitly mention in the requirements.