I have a rest endpoint that has an optional query param.
How and where should I handle this optional
Its an additional filter when I get my data, so basically the DB query that I need to run differ based on the this optional param.
If i add null check for this in the resource handler, and then another if else inside my service to decide what to do that looks like a dirty design. Just because say if I end up with 5 more optional params that can be used to filter same data object then what will I do.
Please help me with what's standard design pattern that i should use here. when to decide that i need a new resource and not put if/else in my existing resources. Is there a more sophisticated way to handle this then please suggest.
I'm Using Kotlin and RestEasy
Related
I am just getting started with REST API and I have a few question. I am not sure exactly when it's best to use query parameters or path parameters or to send data in the body?
Right now I am designing a social media platform, and for example I don't know if when a user adds a comment, how should he use it? Is adding it in the request body the best option?
Please, also explain in general, not only for this example. Thank you!
I am not sure exactly when it's best to use query parameters or path parameters or to send data in the body?
query parameters and path parameters are part of the resource identifier; these tell the server which resource we are talking about.
The information that describes how you want the server to change its resources belongs in the request body.
For example, when I submit this answer to stack overflow, the text I'm currently typing belongs in the HTTP request body.
The real difference between query parameters and path parameters is pretty small: with path parameters, other resources with identifiers in the same hierarchy can be described using relative references; with query parameters, you support the creation of general purpose HTML forms that can be used to compute resource identifiers.
But that's purely a mechanical concern. The machines don't care very much, so you can choose any spelling conventions that make life easier for some humans you care about.
First of all you should decide which method to use:
GET - retrieve data
PUT - update data
POST - create data
DELETE - remove data
For your example with comment I would use POST or PUT depending on your architecture. Normally both of them are used with the "body".
Query parameters are mostly used with GET for filtering etc. when you are obtaining some data.
I'm looking for some guidance/advice/input on the concept of filtering resources when making a REST API call. Let's say I have Users and Posts, and a User creates a Post. If I want to get all Posts, I might have a route as follows:
GET /api/posts
Now if I wanted to get all posts that were created after a certain date, I might add a filter parameter like so
GET /api/posts?created_after=2017-09-01
However, let's say I want to get all posts by Users that were created after a certain date. Is this the right format?
GET /api/posts?user.created_after=2017-09-01
When it comes to filtering, grouping, etc, I'm having a hard time figuring out the right stuff to do for REST APIs, particularly when using a paginated API. If I do this client side (which was my initial thought) then you potentially end up with a variable number of resources per page, based on what meets your criteria. It seems complicated to add all of this logic as query parameters over the API, but I can't see any other way to do it. Is there a standard for this kind of thing?
There is no objective 'right' way. If using user.created_after logically makes sense in the context of your API, then there's nothing really wrong with it.
Personally, I would not use user.created_after.
I would rather prefer one of the following options:
Option I: /api/posts/users/{userid}?created_after=2017-09-01
Option II: /api/posts/?user={userid}&created_after=2017-09-01
The reason is simple: It looks wrong to me to create dynamic query parameters. Instead you can combine the query parameters (Option II) or even define a more specific resource (Option I).
Regarding pagination: the standard approach is something like this: In addition to filter parameters, you define the following parameters: page and pageSize. When constructing the request, client will specify something like page=2&pageSize=25&orderBy=creationDate.
It's important to note that server must always validate the parameters and can potentially ignore or override incorrect parameters (e.g. page doesn't exist, or pageSize is too big may not return an error, but instead returning reasonable output. This really depends on your business case)
I'm designing a RESTful API and I'm asking myself question about the filter field.
On my gets queries I want the user to be able to select the fields he want to get in the response. I was pretty sure that it would be the field filter jobs to give me the requested field but, after some reshearch, I found that most of the time it's used to add criteria on the fields, as a IF. Is it the user that needs to make show or hide the fields ans the Api return the full ressource everytime ?
I got an other question which is about the URI representation of such filter. Should it be something like /foo?fields=[bar1,bar2] ?
Thanks
It's not common to have a resource where you can specify what fields you want returned, by default all fields will get returned. If your resource has a lot of fields or some fields have really big values, it can be a good idea to have a way to specify which fields you want returned.
In REST there are no strict rules about how you should design your URLs for filters. It is indeed common to use GET parameters because they can be optional and don't have to be in any specific order. Your proposal of /foo?fields=[bar1,bar2] seems fine, however i would personally leave off the brackets.
Google Compute Engine API uses the 'fields' request parameter (see the documentation). The syntax is flexible enough to let user select/restrict even the nested elements. You may find it useful.
Yoga is a framework that allows you to deploy your own REST API's with selectable fields. This can reduce roundtrips to the server, and improve performance.
I have a REST API that provides access to a resource using GET.
Using this method I can get a specific instance or all instances.
In this case one instance isn't enough and all is too many.
What I've done is create a new Controller with a pattern like /api/filteredresource and made that a POST request with the body containing a representation of a filter to be used to limit the list of items returned.
I'm not looking for a "How do I..." answer, more a "Should I do it this way..." one.
What's the besrt practice here?
This StackOverflow article seems to suggest I shouldn't do it this way as the data canno (or rather should not) be cached but in this instance caching this filtered data doesn't make sense. I suppose I'm looking for a pragmatic answer rather than a technically correct one.
** EDIT **
The inital requirement was to just search for instances of the resource matching a particular status, but it seems that this was to be a 'first step'. They have a 'search key' that they want to use that contains all sorts of properies matching, in many cases, elements of the resource itself and they want to be able to use this 'search key' (or a representation of it) as the filter.
** END EDIT **
It's fine to use POST for any operation that isn't standardized, but retrieval of any kind is standardized and should be done with GET. As you figured, this depends on how pragmatic you want to be, and how much you want to stick to the standards.
If your problem is that the query string isn't readable or easy to represent, and you really want to stick to REST principles, you should have a query or filter resource subordinated to the filteredresource you want to filter, then it's semantically correct to make a POST with a body of filter parameters. This POST should return a 303 with a Location URI for a GET to the filteredresource, with a querystring that will yield the result you expect. Since this is generated by the API, and doesn't have to be readable, how easy it is to build or read shouldn't be an issue at this point. That URI will be cacheable and you'll be doing your retrieval with GET.
A compromise between pragmatism and purism is having that POST simply returning the result.
If you want to be pragmatic, just POST to `fiteredresource' and don't worry about it.
Use query parameters to filter:
GET /rest/things/1
gets the thing with id=1.
GET /rest/things
gets all things.
GET /rest/things?color=yellow
gets only the yellow things.
I'm just learning REST and trying to figure out how to apply it in practice. I have a sampling of data that I want to query, but I'm not sure how the URLs are meant to be formed, i.e. where I put the query. For example, for querying the most recent 100 data records:
GET http://data.com/data/latest/100
GET http://data.com/data?amount=100
which of the previous two queries is the better, and why? And the same for the following:
GET http://data.com/data/latest-days/2
GET http://data.com/data?days=2
GET http://data.com/data?fromDate=01-01-2000
Thanks in advance.
Personally, I would use the query string format in this case. If your /data path is returning all of the data, and you would like to perform this type of query, I believe it makes the most sense. You could also pass query string parameters such as ?since=01-01-2000 to get entries after a specified date or pass column names such as ?category=clothing to retrieve all entries with category equaling clothing.
Additionally, you would want paths such as /data/{id} to be available to retrieve certain entries given their unique id.
It really depends on a lot of things. If you're using any sort of MVC framework, you'd use the URI segments to define your get request to your API which I personally prefer.
It's not a big deal either way, it's all based on preference and how predictable you want the URL to be to your user. In some cases, I'd say go with the REST parameters, but more often than not a URI based GET is quite clean if your setup supports it.