A Web API For Your Pi

There are many ways to attach a project to the Internet, and a plethora of Internet-based services that can handle talking to hardware. But probably the most ubiquitous of Internet protocols for the average Joe or Jane is the web browser, and one of the most accessible of programming environments lies within it. If only somebody with a bit of HTML and Javascript could reach a GPIO pin on their Raspberry Pi!

If that’s your wish, then help could be at hand in the form of [Victor Ribeiro]’s RPiAPI. As its name suggests, it’s an API for your Raspberry Pi, and in particular it provides a simple web-accessible endpoint wrapper for the Pi’s GPIO library from which its expansion port pins can be accessed. By crafting a simple path on the address of the Pi’s web server each pin can be read or written to, which while it’s neither the fastest or most accomplished hardware interface for the platform, could make it one of the easiest to access.

Security comes courtesy of Apache password protected directories via .htaccess files, so users would be well-advised to consider the implications of connecting this to a public IP address very carefully. But for non experts in security it still has the potential to make a very useful tool in the armoury of ways to control hardware from the little single board computer. It’s not the first try at this idea as we’ve seen a PHP example early in the Pi’s lifetime as well as one relying upon MySQL, but it does seem to be a simpler option than the others.

29 thoughts on “A Web API For Your Pi

      1. from cgi import parse_qs
        
        data = parsq_qs( environ['wsgi.input'].read() )
        

        That’s how you access a POST on WSGI. I’m not lazy or stupid. I decided to use GET cause I had an ideia on my mind. I’m now considering PUT or POST, but GET was very simple to anyone.

        Turn on the Light

        or

        fetch(‘rpiapi/activate/1’)

        Anyways, I’ll consider the things I read here on my next iteration.

      2. This is an example of where sticking rigidly to REST principles is not necessarily helpful to the end user. Disregarding the arguments about GET vs POST, etc. The use of verbs in the URLs actually makes the API very transparent and the need for documentation a lot more minimal. (Just because it’s a standard doesn’t mean it’s easy to use/understand)
        For a beginner user getting into this sort of thing, at first glance it seems like a really nice introduction to talking to GPIO. If I wanted to go much further, or scale a system beyond hobbyist stuff, I may look at other libraries and be concerned about best practices, etc. but for showing a kid how to make a light flash with some HTML, I’d probably choose this.
        Good job Victor, I hope you can keep developing this, but I like the URLs :)

    1. What kind of request/method would be resilient?
      https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
      “Applications can be developed to only accept POST requests for the execution of business logic. The misconception is that since the attacker cannot construct a malicious link, a CSRF attack cannot be executed. Unfortunately, this logic is incorrect. There are numerous methods in which an attacker can trick a victim into submitting a forged POST request, such as a simple form hosted in an attacker’s Website with hidden values. “

      1. It’s a bit of red herring. Generally, you don’t want your Pi open to the world without authentication, anyway. These kind of APIs generally aren’t done through web browsers, either. If you want to protect against CSRF, it needs to be through a CSRF token.

        That said, best practices are not to modify state with GET requests. It tends to break client assumptions. For example, some old “dial up accelerators” worked by prefetching every link on the page. Web-based file managers would have a delete link, and those accelerators would dutifully follow it.

      1. The big issue is that if you present your web api as a do-it-all solution/framework for everyone to import into their projects, then you also *must* consider security, standards and general good practices.

        Because basically it’s just not so hard to add any sort of web api to your raspberry pi or your ESP8266 or whatever. Anyone can do that with a few lines of code.

        But not everybody is capable of doing it in a secure and standardised way, AND following good practices. Your web api should really have some significant added value over custom-made code, in those areas.

        Otherwise it’s just better for people to write their own custom code. Because their api will then be custom, not open, and at least give some security-by-obscurity. You published your api, so the security-by-obscurity advantage is not there anymore.

        I’m not saying that security-by-obscurity is a good thing. :) But it does have some security advantages over no security at all. ;)

  1. It is an API but not following RESTful principles (as has been pointed out).

    Normally you would identify the resource and use the HTTP Verbs to act upon the resource. For example:
    GET->/api/v1/gpio would return the state of all pins
    GET->/api/v1/gpio/1 would return the state of pin 1
    PUT->/api/v1/gpio/1 with a value in the body (formatted as JSON, XML, etc) would set the state of pin 1 to that value
    and so on…

    An API structured this way can include other resources such as GET->/api/v1/cpu/temperature, GET->/api/v1/cpu/utilisation, etc. The /v1 part allows for future versions which can coexist with the previous versions.

    1. Yes, I was thinking “what makes more sense?” when selecting the endpoints, so I end up using activate / deactivate. I have a chat bot project that I can just say “activate 5” and it would. That’s also one of the reasons all my endpoints are GET, sou can access them with a simple link

  2. Instead of the usual HaD celebration or roasting of mediocrity (which it is) let’s make this a learning experience:
    -No way to set multiple GPIO at once.
    -Everything is GET as others pointed out. Idempotent state modification should use PUT, as in changing the mode of a pin.
    -ADC read should be initiated with POST
    -Cache-Control usage is here…seems like he found that out the hard way using a web browser
    -Responses lack timestamps or sequence numbers
    -Client should be able to request Content Type

    He’s an undergrad, so don’t pick on him too hard

    1. I can fix all those things you mentioned, but I can’t fix that attitude. If you don’t like the project and don’t intend to use it or help build it, the next best thing you can do is be polite. I sacrificed my weekend to create this simple but working project.

      1. I am not trolling you Victor. But you must realise that many people here sacrifice their health and/or personal life creating complex and working projects. :)

        Just take it as a free lesson by someone who is very much more professional and experienced than any of your professors.

      2. “I can’t fix that attitude. If you don’t like the project and don’t intend to use it or help build it,”

        He said, with a demonstrable bad attitude towards constructive criticism.

        Seriously, the post you replied to was helpful, full of good, well structured advice, and called for people not to give you a hard time, and this is your response. Wonderful.

          1. Victor, I have been in industry for decades. People will be kicking you down for years when you start your career. Dare to do something different and you will be called a heretic. When you find a demonstrable compiler bug in TI’s msp430 compiler, you will be called out for writing unusual code. When you reorganize data in a way that highlights the core patterns people will call it overengineered.

            In this case the different thinking was putting a web API on something typically done on the lowest level. In this case the web API was really mediocre and need improvement. Keep working hard.

          2. Shame you didn’t actually keep the context of the actual quote:

            “Instead of the usual HaD celebration or roasting of mediocrity (which it is) let’s make this a learning experience:”

            Seems like you’re unlearning things with each reply….

    1. This sort of thing is usually implemented in a language-specific application framework (like Express.js). If it’s exposed to the rest of the world, it’s probably through a frontend proxy that handles authentication and TLS. Nginx makes a good frontend proxy.

  3. I discovered another reason not to change state on a GET when I did a garage door opener years ago. Whenever my wife opened up the web page used to control the garage door and lights, it refreshed the last used URL such as /garage/door/open and the door opened. A post is never automatically resubmitted.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.