Introduction

In this post we will build an API(Application Programming Interface) for the webserver we built in Part 2.

What is an API?

A regular webserver formats it's content in such a way that it can easily be displayed on a browser for the user to see. This is fine for most use cases, however sometimes we want the webserver to be able to communicate with other programs(like a mobile app). While it is possible to this with a regular webserver, we realize that alot of the returned data is unnecessary for the other programs. To illustrate this, I will use the webserver we have already built.

Now when you navigate to the page on that server, there is a lot of extra information visible(like the table headers etc). An external program doesn't need that information, in fact most of the time, external applications will want to incorporate their own user interface. This is why the concept of an API was created.

In our webserver an external program needs to know only 2 things, how to get a list of all the available pin numbers, and how to toggle each pin.

JSON

JSON(JavaScript Object Notation) is a "language independent data format". What this essentially means, is that it is a standard way of describing data objects. This is great because it doesn't matter what language the client application is written in, it will be able to encode/decode any JSON object.

We will be building a JSON API.

Building the API

As mentioned earlier, I will be adding the API to the webserver we built earlier. The code can be found on the Github Repository. I'll explain all the additions here:

  • We first add a few imports that we will be using:
        import json
        from StringIO import StringIO
  • We then extract the part of the old toggle function that actually toggles the pin to a new function, the reason we do this is because that code will be reused and we want to minimize duplication as much as possible. We have also added a check to this function to make sure the pin number given exists in our list.
        def togglePin(pin):
            try:
                current_values[pin] = not current_values[pin]
            except KeyError:
                return "Invalid Pin number"
            GPIO.output(pin, current_values[pin])
            return "Ok"
  • Now for the real stuff. We create a new route at /api/list that will return the list of all available pins. To do this, we first confirm if the request is a JSON request, if not we return an error. We then create a JSON object of the list and dump it into a string to return.
        @route('/api/list')
        def api_list():
            if request.environ['CONTENT_TYPE'] == "application/json":
                io = StringIO()
                json.dump(current_values, io)
                response.content_type = "application/json"
                return io.getvalue()
            else:
                response.status = 400
                response.content_type = "application/json"
                return "{'Error': 'Only JSON requests accepted'}"
  • We then create another route at /api/toggle which takes in a pin number and toggles it. As you can see the code is exactly like the old toggle function, with the addition of the JSON and Pin number Checks.
        @route('/api/toggle/<pin>', method="POST")
        def api_toggle(pin):
            if request.environ['CONTENT_TYPE'] == "application/json":
                response.content_type = "application/json"
                if togglePin(int(pin)) == "Ok":
                    return "{'Success': true}"
                else:
                    response.status = 400
                    return "{'Error': 'Invalid Pin Number'}"
            else:
                response.status = 400
                response.content_type = "application/json"
                return "{'Error': 'Only JSON requests accepted'}"
  • And those are all the changes. We now have a functioning JSON API.

  • You can test it from your command line using the curl command

    • curl -H "Content-Type: application/json" http://<IP>:8080/api/list
    • You should get a response like this {"24": false, "18": false, "23": false}
    • We can then toggle a pin with url -H "Content-Type: application/json" -X POST http://<IP>/api/toggle/18
    • This should give a Success response {'Success': true}
    • You can confirm by calling the list command again and see the new status, which should now return {"24": false, "18": true, "23": false}

Conclusion

External Applications can now control your Pi using the API. Stay tuned, the next series will build native Mobile Apps to take advantage of this API