GraphQL for Consumer IoT Applications
At Yonomi, we have to satisfy a wide array of requirements from our customers. We are savvy in event-based architecture, pub/sub protocols, and we work within the limitations of hardware: memory, battery, and internet availability. We also have to iterate quickly and expand functionality across a myriad of devices.
In the last year, we have learned a lot about GraphQL and have discovered some great features that may benefit the IoT industry and specifically, our customers in consumer IoT.
GraphQL has a powerful built-in schema and a strong type system that serves as basic documentation for the API. The schema is facilitated by the GraphQL Schema Definition Language (SDL), which allows us to define a device’s type. You can learn more about SDL here. Once defined, the client and the server have a contract on parameters and values.
For example, a Light device type may need to define the device’s name that the end user calls their light, whether the light is on or off, and what brightness the bulb is currently set to.
With custom schema directives, we can take this a step further and define which attributes are stateful for a device type. In such cases, we can make a mutation request to set the state of that attribute on the device. When the device accepts and acts on that request it can respond with the new state of that attribute.
The custom schema directives let the client and server know which attributes are statefully managed by the device. Users can request to set the state of those attributes but, in the end, the device manages the actual state that it is in.
Self-documenting APIs makes GraphQL ideal for consumer IoT where you need to control device’s attributes and states. The schema functions as a contract that both the client and server have to fulfill while exposing how the device functions. In the example of the Light type above, the Light’s name has to be a string, and the power and brightness attributes are stateful where only the device can report its state to the cloud. A user can tell the device to set a state but ultimately, the device is the source of truth on whether the request is accepted or not.
We initially considered GraphQL when our customers wanted more control over the data they requested. They also wanted access to related data with as few requests as possible for mobile applications. GraphQL is a natural choice for this because of its ability to refer to related data through the type definitions that define the schema of the object/model.
A great use case for this would be associating devices to locations. In consumer IoT, we associate devices to rooms within a house for products that are wanted in many rooms, like light bulbs. Our mobile app, in this case, would list devices that are in rooms all associated with a single house location. When a user wants to make sure the lights are off while on vacation, they can check the status of all the lights throughout the home and only make one API request.
This problem is commonly referred to as the over/under-fetching problem. In a RESTful architecture, you would normally make at least two requests to be able to obtain all of this data (under-fetching) and would have obtained more information than what you really needed (over-fetching). Over-fetching data could be extremely detrimental to a device that cannot handle unknown attributes or is limited in memory. By over-fetching data, a device is susceptible to buffer overflow, which overruns the buffer's boundary and overwrites adjacent memory locations. Letting devices control which data they want to work with and not having to worry about receiving more data than what was requested alleviates this problem entirely.
Mobile developers have also become innately aware of data consumption and strive to use as little as possible when they can. GraphQL enables minimizing data use through data relations that are defined in the schema and allowing the clients to be selective in their queries.
As a cherry on top, Apollo server supports subscriptions out of the box. Subscriptions are GraphQL operations that watch events emitted from Apollo Server. The native Apollo Server supports GraphQL subscriptions without additional configuration.
GraphQL clients can get near real-time information on device’s states as they change. No need to poll for the device’s current state, just subscribe and listen for those changes as they happen. This works really well for app-clients that want to show device status changes as soon as they are available.
Although these features of GraphQL are nice, there are some caveats when selecting relatively new software for production environments.
Apollo and Prisma have been pumping out an impressive amount of tooling for GraphQL and things are only getting better with community support. Yet, there are a few things that are still hard to do, and everyone is doing things differently. Namely, acceptance testing.
At Yonomi, we are working on our own acceptance test tooling and one day we hope to share these with the community.
In GraphQL everything is 200 OK.
Did you make a bad Query or Mutation? 200 OK.
Internal Server Error? 200 OK.
Not permitted to access that data? 200 OK.
As long as you hit the GraphQL server you will receive a 200 OK. As cloud experts, we have learned to rely on HTTP statuses to provide helpful and standard information. GraphQL has decidedly been remiss on some of the golden standards of HTTP.
In GraphQL, every field is nullable by default. There are many ways for things to go wrong when interacting with n-number of databases, services, etc. to perform a single GraphQL request. So, if any of them fail, GraphQL will simply return null for that attribute or parent attribute. Although this is a design choice, it is something worth noting when working with GraphQL. If your clients rely on null values to mean more than the value simply wasn’t returned by your API, you might run into problems. The wonderful people at Apollo offer sound advice on this here.
Many benefits of GraphQL for Consumer IoT
GraphQL has the ability to self-document with its schema, can simplify API interactions to only one request, allows requests to specific fields, and it provides simple to use subscriptions to access real-time information. Although it has some weakness when considering available tooling and thinks everything is 200 “OK”, GraphQL provides a lot of power for use-cases specifically required by the internet of things. At Yonomi, we are continuing to learn and explore more on how GraphQL can better suit the needs of our customer’s now and in the future.
Are you building a consumer IoT device?
Check out our free Guide to Building a Connected Device