arduino / arduino-create-agent

Arduino Cloud Agent
GNU Affero General Public License v3.0
420 stars 149 forks source link

Expose a /list http endpoint #163

Open rakeshpai opened 7 years ago

rakeshpai commented 7 years ago

Using a streaming API like WebSockets is awkward for request/response type communications. A GET /list would feel much more natural.

facchinm commented 7 years ago

In fact, the request/response is only true for the server issued commands, while the serial output is totally unattended (once you open the port) so WebSockets are a better choice for the latter. REST APIs would be much more natural for client/server communication but require an extra implementation on both sides. If you wish to add this feature we'll be very glad to review and eventually merge it! Thanks!

rakeshpai commented 7 years ago

Thanks, @facchinm. I'm sorry, I don't have any experience with Go. I'd have loved to contribute to the code! However, I do have some experience with designing APIs. Here's how I'd do it. (I know this is unsolicited opinion, so feel free to ignore it. Also, I apologise if I'm annoying you with too many comments/issues.)

The serial connection and websocket connection are similar in that they are both full-duplex streaming connections. So, they are are analogous to each other, and could be made to mirror each other. HTTP connections are request/response type - so, ask a question, get an answer type scenarios are best handled with HTTP. So, these are the changes I'd make:

I'm looking at this from the perspective of browser JavaScript, consuming the API provided by the agent.

  1. When the browser opens a WebSocket connection to the agent (which could be to say a path like wss://localhost:1234/?port=/dev/ttyUSB0&baud=9600, the server opens a corresponding serial connection, and sends the input of one stream to the other and vice-versa. When the client drops the stream, the server drops the serial connection
  2. This eliminates the need for commands like log on or open or close, making the agent code simpler, and making client implementations easy as well. There would be no need to wrap the messages in a JSON either, like the {D: '...'} messages right now. So, basically, all serial-related data processing on the agent can be eliminated.
  3. Including the port and baud as query-string parameters in the URL also allows for multiple simultaneous independent socket connections, which means that users can simultaneously open multiple serial connections by opening multiple WebSocket connections, and keep their messages distinct, which the current implementation doesn't allow.
  4. What remains can be moved over to HTTP. /info and /upload is over HTTP already. /list can be moved over to HTTP, which (IMHO) feels natural, since it's a request/response type call anyway. The last thing that remains is the download command. I'd recommend that you don't expose this at all, and automatically decide if you need to download tools, based on the POST payload JSON of the /upload call.
  5. Stop using socket.io. Socket.io is not just WebSockets. It's a communication framework, using one of many network transports (including, but not limited to, WebSockets). It uses an one-the-wire protocol, which every client has to implement, essentially making the socket.io protocol part of your API. All clients are forced to use a socket.io library - in my case it added 18k to my JS, after minifying and gzipping. That's a tax that all developers and ultimately all users have to pay because of the choice of communication technique. Use plain WebSockets instead - you won't need socket.io with the above implementation anyway, and WebSockets are standard in the browser and don't need any additional libraries for use.

Feel free to ignore comments above, but I'm also open to discussion. I hope I'm not meddling too much - I really like this project, I think it solves a real problem, and having the Arduino brand behind it is very valuable. Cheers!