RESTful API echo server using Python bottles I just wrote an echo server that responds to curl requests with the method used and the data sent. Sticking to GET and POST for now, but I would like to know if there's something I can do to improve my RESTful API.

I'm supposed to:


Only be able to call the /data endpoint
Only allow JSON parameters 
Use best practices of coding a RESTful API


Expected JSON response:

{
  "method": &lt;HTTP METHOD REQUESTED&gt;,
  "data": &lt;HTTP PARAMETERS SENT IN THE REQUEST&gt;
}


Here is my current code:

from bottle import run, post, request, response, get, route, put, delete
from json import dumps
import json

@get('/data')
def data():
    #if headers are not specified we can check if body is a json the following way
    #postdata = request.body.read()
    postdata = request.json
    try:
        #rv = {"method": request.method, "data": json.loads(postdata.decode('utf-8'))}
        rv = {"method": request.method, "data": postdata}
    except:
        raise ValueError
    response.content_type = 'application/json'
    return dumps(rv)

@post('/data')
def data():
    #postdata = request.body.read()
    postdata = request.json
    try:
        #rv = {"method": request.method, "data": json.loads(postdata.decode('utf-8'))}
        rv = {"method": request.method, "data": postdata}
    except:
        raise ValueError
    response.content_type = 'application/json'
    return dumps(rv)


Everything seems to work fine for now. I'm looking to improve my code so any feedback is appreciated.
The code looks a bit incomplete, e.g. shouldn't there be a main method
somewhere?

I added the following to get it to run for now:

if __name__ == "__main__":
    run()


It's good practice to have the __name__ check in there instead of just
executing, because then you're still able to import the file elsewhere
without it automatically executing code.



Okay, so with that out of the way, there's commented out code that
should be there:  Either it's correct, then it should replace the
uncommented code, or it's not, then it should be deleted.  To me,
reading that just confuses me what the purpose is, or was.

And then there's two functions, which are identical ... why is that?  I
suppose that's a feature of the framework that allows you to have both
functions because of the annotations, but generally do not do that and
give them separate names, at least something like
data_get/data_post.

The specification is pretty vague, what are you supposed to echo, the
POST body, or the URL parameters?  Because then I don't get what the
GET one is supposed to be doing.  With that in mind I'd delete it.

So, then, trying it out:

&gt; curl -d '{"data": 1}' -H "Content-Type: application/json" -v http://localhost:8080/data
{"method": "POST", "data": {"data": 1}}%


Seems to work.

(Also, since there's a single endpoint that echoes data ... there's
little REST here.  I'm not sure what other best practices are meant to
be followed for this exercise.)

I've no idea how you'd get an exception in there, but in any case,
raise ValueError isn't super helpful, it says exactly nothing about
what went wrong.  Consider adding some information like raise
ValueError("Couldn't format data.").  Note that in this particular
situation there's little that adds information, maybe don't catch the
exception then.

At that point it might look like this:

@post("/data")
def data():
    response.content_type = "application/json"
    return dumps({"method": request.method, "data": request.json})




However, then I was thinking, maybe this framework does the JSON
formatting for us.  And it does:

@post("/data")
def data():
    return {"method": request.method, "data": request.json}


Probably can't get it much smaller than that actually.  And then you can
delete a lot of imports too:

from bottle import run, request, post
from json import dumps




Hope that helps.  In general it's good to let readers know all you can,
like "which dependencies do I need" and "how do I run this", including
example invocations.