How to Query LightDB Stream Data the Right Way (POST vs GET)

Recently, we’ve seen an uptick in questions about our LightDB REST API Stream endpoints. And to be honest, it’s not surprising. 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 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 Can I Use Both POST and GET?

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.

Breaking It Down

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.

Conclusion

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!

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

Custom Board, Custom Zephyr Devicetree (AirTag Session 3)

Sign up for the AirTag Clone webinar series to watch Golioth build out board definition files for the Orleon board, a Bluetooth sensor platform/playground. The upcoming session on May 23rd will walk through setting up all required build files.

Where’s my (Bluetooth) drill?

We implemented Golioth's Bluetooth-to-Cloud connectivity on a battery pack on a commercial power drill. We not only monitored power usage of the drill, we also looked up the location of the most recent gateway we connected through and attached that to the drill's device record.

Battery Monitoring with Zephyr’s Fuel Gauge Subsystem

Fuel gauge ICs offload effort when it comes to taking reliable battery readings and estimating charge and drain times. Zephyr's support for these components makes using them even easier.

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.