LightDB Stream API: POST vs GET for IoT Device Data Queries | Golioth

This article explores how and when to use POST vs GET when querying the Golioth LightDB Stream API for IoT device data.

Recently, we’ve seen an uptick in questions about our LightDB Stream REST API Stream endpoints. And to be honest, it’s not surprising. For those who aren’t familiar, Light DB Stream is a time series data store within the Golioth Platform. As someone with a background in embedded systems, I’ll be the first to admit that Cloud and REST APIs weren’t exactly in my comfort zone when I started digging into this. When I first looked at querying data from the cloud where I had sent my data…I was confused too. Add to that the inherently multidisciplinary nature of IoT, where you’re expected to juggle hardware, firmware, and cloud software, and it makes total sense why there’s a lot of confusion around how to properly use these endpoints.

Some engineers are wizards with firmware but have barely touched a cloud dashboard. Others can deploy a Kubernetes cluster blindfolded, but would rather avoid debugging an I²C bus. The diversity in background and skills is part of what makes IoT so exciting—and so complex.

We’ve been hearing your questions, and in the spirit of building a better platform (and explaining it along the way), let’s discuss the LightDB Stream endpoints and when to use POST and when to use GET requests…and whether there is a Right™ way.

LightDB Stream API Endpoints Overview

If you poke around our OpenAPI docs, you’ll see a few endpoints under LightDB Stream:

  1. GET/POST /v1/projects/{projectId}/devices/{deviceId}/stream
    • This lets you query stream data for a specific device. You can filter by time, path, and other parameters
  2. GET/POST /v1/projects/{projectId}/stream
    • This lets you query stream data across all devices in a project—helpful for dashboards or fleet-wide analytics

At first glance, they look pretty straightforward. And most people can guess what they’re supposed to do. But then you notice that both support both GET and POST. That’s when things get murky. If the device is posting data to Golioth, why would the client also post to read it? Shouldn’t GET be enough?

That’s exactly what I thought—and where the deeper story begins.

Why POST and GET Methods Both Work for Data Queries

The biggest head-scratcher tends to be: Why do both endpoints accept both GET and POST?

GET makes sense—it’s how we typically request data from REST APIs. Like going to a deli and ordering the number 4 sandwich one the menu. But why would I POST to an endpoint just to fetch something? Isn’t that what my device does when sending data?

One of our forum posts recommends using POST when querying LightDB Stream, which feels backward until you understand what’s going on under the hood.

When to Use POST vs GET for LightDB Stream

Let’s compare the two in the context of:

  1. GET/POST /v1/projects/{projectId}/devices/{deviceId}/stream
  2. GET/POST /v1/projects/{projectId}/stream

Yes, both can be used to query data—but we recommend POST for a subtle (yet important) reason: POST allows complex queries in the request body.

LightDB Stream supports advanced queries—things like filtering by specific fields, defining time ranges, and setting limits. To represent all of that, you need a structured way to pass the query. That’s where POST shines. To go back to the deli analogy, this is like ordering a complex sandwich just to your standards, instead of only asking for sandwich #4.

With POST, you can include your query as a clean JSON payload in the request body. Here’s what that might look like:

{ 
  "start": "2025-05-01T09:00:00+00:00", 
  "end": "2025-04-29T12:00:00+00:00", 
  "query": { 
    "fields": [ 
      { 
        "path": "time", 
        "type": "" 
      }, 
      { 
        "path": "deviceId", 
        "type": "" 
      }, 
      { 
        "path": "temperature", 
        "type": "" 
      }, 
    ], 
    "filters": [] 
  }, 
  "page": 0, 
  "perPage": 10 
}

Trying to squeeze that into a GET request would quickly turn into a mess. The URL would be long, fragile, and hard to read or debug. It might even break in certain browsers or proxy layers. And while some clients technically support request bodies with GET, it’s against HTTP spec and not something we recommend.

Using POST gives you a more expressive and flexible way to query data. You’re not bound by URL encoding or the limitations of query strings, and the result is cleaner, more maintainable, and more predictable across different tools and environments.

The equivalent GET request would look like this:

curl -X GET \
  "https://api.golioth.io/v1/projects/{projectId}/stream?start=2025-05-01T09:00:00%2B00:00&end=2025-04-29T12:00:00%2B00:00&fields=time,deviceId,temperature&page=0&perPage=10" \
  -H 'accept: application/json' \
  -H 'x-api-key: YOUR_API_TOKEN'

GET request is useful for quick tests in a browser or a command-line tool. But as soon as your query gets more complex, with time-based filters or multiple fields, switch to POST. It’s more robust, scales better, and won’t break when your query grows.

Final Thoughts on GET vs POST for Queries

To wrap things up: while both GET and POST can be used to query LightDB Stream, they serve different use cases depending on the complexity of your request. GET is great for quick, simple lookups—think of it as your go-to for ad-hoc testing, browser-based exploration, or lightweight queries with just a few parameters. It’s familiar, fast, and easy to drop into tools like curl or Postman when you’re just poking around.

But when your query starts to grow, maybe you need to filter by time ranges, select specific fields, paginate through large datasets, or apply more advanced logic, POST becomes a better tool. It allows you to express your intent through a structured JSON payload, which is not only more readable and maintainable but also avoids the pitfalls of overly long or fragile URLs. More importantly, POST ensures your queries remain compatible across different clients and environments, especially when working at scale or integrating with dashboards and analytics pipelines.

In short, use GET when you want simplicity. Use POST when you want power, flexibility, and clarity.

If you’re building with LightDB Stream and run into questions—or just want to bounce ideas off other developers—you’re always welcome to reach out on the forum. Our team and community are there to help, and we love hearing how you’re using these tools in the real world. Let us know what you’re building!

Other posts you may want to explore:
How To Manually Send Data to LightDB State and LightDB Stream
New Pipelines Data Destination: LightDB State

Marko Puric
Marko Puric
Marko is a Field Applications Engineer (FAE) at Golioth. He helps Golioth customers bring their proofs-of-concept to life, and works with them to overcome initial integration challenges. This effort ensures successful integration of the Golioth Platform into new development and production environments.

Post Comments

No comments yet! Start the discussion at forum.golioth.io

More from this author

Related posts

spot_img

Latest posts

Use the ESP32 AT Binary to Make Any Zephyr Project Wi-Fi Enabled

You can add Wi-Fi to any Zephyr project with an ESP32 running the ESP-AT firmware and a couple of configuration symbols in Zephyr. Let the data flow!

The ESP32 HCI makes any Zephyr board a Bluetooth gateway

Bluetooth HCI enables any chipset to act as a peripheral to a processor running a Bluetooth stack. We pair the ESP32-C3 HCI with a processor running Zephyr to turn Golioth's development platform--the Aludel Elixir--into a Bluetooth gateway.

A Remote Shell for Embedded IoT Devices

Golioth's Remote Shell uses Remote Procedure Calls (RPCs) and a custom Zephyr shell backend to enable an interactive, web-based shell experience from anywhere in the world.

Want to stay up to date with the latest news?

Subscribe to our newsletter and get updates every 2 weeks. Follow the latest blogs and industry trends.