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

How to Sniff Cellular Packets with a Nordic nRF91

Sniffing network packets from a cellular modem is actually pretty easy. It only seems daunting because at first glance you're left wondering how to acquire the packets. Nordic's nRF91 modems have a trace capability that can be used to pipe packets from the device into Wireshark over a USB connection. Here's how to use it.

The Demo We Show To Our Biggest Customers: A Full Golioth Cloud Demo

Want to see everything Golioth can do? In this post, we highlight all major parts of the Golioth console and how an IoT device can deliver a range of services between Cloud and Device.

OTA: Working with Multiple Images

OTA usually makes people think of updating firmware. But OTA also covers many of other applications, like distributing new machine learning models, UI image assets, or firmware updates for other "downstream" processors. Golioth has the flexibility to support all these use cases. Here's how to use the power of the Golioth OTA service when you need to deploy more than just one binary.

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.