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

Enabling Bluetooth-to-Cloud on the STM32WB5MM-DK

Golioth makes it easy to connect Bluetooth devices to the cloud. Load provided binaries to create a Bluetooth gateway, then use reference Zephyr code to connect BLE devices from your fleet to the Internet. Here we show how to add an STMicroelectronics dev board as a leaf node in your fleet.

Upcoming webinar: Batteryless Cellular IoT with Conexio

We're excited to be hosting a new webinar coming up on June 18th at Noon ET / 9 am PT with Rajeev Piyare of...

Detecting Text From Images Over A Cellular Link

This post and video demonstrate taking a photo with a low power camera and cellular-based microcontroller and transmitting to the cloud for processing. Rick Jen from the Microsoft Azure team shows how to accept those images and work with the Azure AI OCR service to extract useful text and store it in a database.

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.