Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Dealing with GETs with long query strings in ASP.NET Core
One of the recent business requirements is to be able to search through a list of entities using a bunch of filters. Most of these filters allow multiple values and the user might theoretically provide more than 100 selected filter values (some of the filters are even implemented as tree views due to the rather large number of items).
Under normal circumstances, I would define a GET endpoint which "binds" all filter values and does its job. However, this means that a query string might be very long:
/api/entities/list?param1=val1¶m1=val2.... ¶m1=val10¶m2=val11&....
This Q&A provides the query string limits for various browsers and most of them seem to be at least in the tens of KB (of characters).
This should be enough for me (the application is used only in Chrome and Firefox), but there seem to be security and performance implications that lead to 2K as the recommended limit.
A quick option would be to go against the REST "purity" and replace the GET with a POST and the limit would not matter. An alternative would be using GET with a body, but this is not recommended either.
I am wondering if there is a guideline related to how to proceed in such cases.
For my particular case, since the API method is consumed only by a SPA developed by the same team, I can virtually take any approach:
- I will not hit the limits of the browser
- The normal scenario involves an AJAX call with the long query string (from SPA or SwaggerDocs), not necessarily to work in the browser
- I can change some hosting server limits if I need to
- I am not actually forced to use REST API guidelines (although I would really like to develop according to standards)
1 answer
tl;dr Just use a POST. There's likely literally no reason not to in your situation.
- REST is not a standard.
- Being RESTful in and of itself is not a virtue.
- I strongly suspect that your current code/API design violates the guidelines of REST more often than it follows them so there's little reason to be "puritanical" here.
- It also seems pretty clear that your use-case isn't the situation REST was designed for.
REST was designed for handling long-lived, large[1] slowly changing hypermedia documents shared between different organization domains, e.g. different companies. From the details you given and just base rates, I suspect this isn't the situation you're in so there's no reason to expect REST to be an appropriate pattern for your use-case. This isn't to say that there aren't ideas in REST that would be useful for you, but you need to evaluate them for your use-case, and you certainly should not feel remotely constrained to adhering to REST guidelines.
Instead, you "just" need to think about the needs of your application and the engineering costs of various choices. You can frame this as an analysis of the motivations for REST's design choices and how they apply to your particular situation, or you can just do it from first principles. For reasons, I'll take the former approach though there is absolutely no reason to anchor your thinking to REST for this.
From a REST perspective, the main motivation to use GET is that it communicates that a document can be cached. I suspect you aren't doing any HTTP level caching of these requests and likely would actively not want that. Also, with such selective filters, (long-term) HTTP-level caching may not be that effective anyway.
Another important aspect of GET from a REST perspective is that GET is assumed to be safe repeat, i.e. it a GET request has no (significant) side-effects. A POST request does not suggest that guarantee[2]. This makes retrying and prefetching easier and more natural. In your situation, your SPA knows the semantics of the endpoints its making requests to so this isn't an issue.
While not really a GET/POST distinction but rather a URL parameters/request body one, one benefit of having URL parameters is that it allows you to easily bookmark pages. This doesn't seem relevant in your circumstances as it sounds like these URLs are never in the browser's address bar and in some cases this isn't even being accessed by a browser. There are also other ways to accomplish this flow if it was desired that may be better (or worse), e.g. providing the ability to "save a query" as an application-level feature.
There are potentially other concerns that could be considered, but ultimately I suspect that there aren't any compelling and applicable benefits to using a GET request here. Even from a REST perspective using a POST when you could use a GET is at worst "sub-optimal" rather than "incorrect". There are some potentially compelling reasons to prefer a POST here.
What I would do based on my guess at your situation is likely to switch to a POST request and pass the parameters in the body. In fact, I'd most likely have written it that way in the first place as I don't like passing significantly structured data as URL parameters. That said, if I was reasonably confident that the GET approach would be unlikely to cause problems, I could switch to the POST approach quickly, and that my "customers" wouldn't be too annoyed if I was wrong about it being a problem, I would probably not have making the change to POST be a high priority. Basically, switching to POST now means you can stop worrying about it, but you also probably have more important things you could be doing so...
I would strongly avoid any solution that required changing server configurations or, like a body in a GET request, may get mishandled by some web server or other piece of infrastructure. It's extremely hard in most setups to maintain a connection between the motivation for server configuration and code that depends on that server configuration. This leads to either the server configuration change being undone by someone who doesn't know better or upgrades or redeployments, and/or to sub-optimal server configurations to support code no longer exists.
0 comment threads