I am teaching myself REST API development. As part of this, I am creating a Java web server. However, I am stuck on something, and don't know how to proceed.
I have an endpoint called /users, through which users will GET the data. However, I want to implement the option of finding a user and limiting the number of users returned. For example:
GET /users/300 should return the user with ID 300.
If I get the query GET /users?count=10, I want to limit the return to 10 users.
For this, I have settled on the using #QueryParam and #PathParam. The question is: Can I use both of them in the same method?
For example:
#Path("/User")
#Produces({"application/json"})
public List<User> getUsers() {
// ...
}
#GET
#Path("/{id}")
public JSONObject getUserwithId(#PathParam("id") int id) {
return jsonObjectwithId;
}
#Path("?count")
public JSONObject getUserwithCount(#QueryParam("count") int count) {
return noOfusers;
}
I want to whether this is possible.
Yes, I have done this before on web services I have personally worked on. It's not that common, since REST interfaces just don't usually merit the needed complexity. But, it is perfectly permissible for #QueryParam and #PathParam to be used by the same method. I see that you are using Jersey. Based on this thread, if you are actually using Jersey 1.x, you may need to upgrade if you are currently having issues.
Related
I've already read lots of topics about it, but still haven't found the better approach.
I have a User. One User may have many Posts. Users and Posts are different microservices. I'm using Spring Boot.
When the front-end call my Posts microservice sending a POST request to /posts/user/1, I need to check if the given userId (1) exists on my Users database. If no, throw an exception telling the front-end that the user doesn't exist. If yes, then insert the given request body as a Post.
The question is: how should I check this information at my backend? We don't want to let this responsibility with the front-end, since javascript is client-side and a malicious user could bypass this check.
Options:
REST communication between the microservices. (Posts microservice call Users microservice asking if the given id exists on his side)
Give Posts microservice access to Users microservice's database
I understand that communication between them will create coupling, but I'm not sure if giving Posts access to Users database is the best option.
Feel free to suggest any options.
You have an option to do interprocess communication between Post and User microservices through RESTful approach.
In case if you just want to check the existence of the resource and don't want any body in response then you should perfer using HEAD http method. Therefore your API endpoint hosted at User microservice will look like -
HEAD user/{userId}
Call this API from Post microservice.
Return 200 / OK if user exist
Return 404 / Not Found if user does not exist
Click here and here to get more details on HEAD method usage and use cases.
For this very particular use case, if you have a security layer, you can(should) make use of user access token, to ensure, that request is processed for the right user, which can be done by validating the token and relying on the fact that if user has token he exist. (As its just not about if user exist)
For any logic other than that, say you want to check if he is allowed to post or other such restrictions it is required to make a call to the user service.
Talking about giving access to the database, it will be against one basic guideline of microservices. Doing so will form a tight coupling between you and user. Its ok to call user service in this case which can decide how to serve this request.
User service on its part should provide ways to answer your queries within the SLA by caching or other mechanisms.
One more thing that you can explore is BFF (Backend for Frontend)
You rightly said you should not expose backend services to frontend or add any logic there, but often frontend pages may not be comfortable in accepting that content on same page is answered via n different back end services and there might be some logic to stitch such queries and thats where you can make use of BFF.
Backend server (in my case node) which take of things like these requiring frontend to make just one call(or less calls) for a given page and at the same time hiding your backend services within.
You're right, you must do a validation at the back end since, I suppose, it's a REST service and requests can be send not only from the UI.
Suppose you have a service implementation:
#Service
class UsersServiceImpl implements UsersService {
private final Users users;
public UsersServiceImpl(Users users) {
this.users = users;
}
#Override
public void addPost(long userId, Post post) {
User user = users.get(userId);
if (user == null) {
throw new UserNonExistent(userId);
}
user.addPost(post);
}
}
where Users is an interface representing a users database and UserNonExistent is a RuntimeException. Then in your controller you can do the following:
#RestController
class UsersController {
private final UsersService usersService;
public UsersController(UsersService usersService) {
this.usersService = usersService;
}
#PostMapping("/posts/user/{userId}")
public void addPostToUser(#PathVariable String userId, #RequestBody Post post) {
usersService.addPost(userId, post);
}
#ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "User does not exist")
#ExceptionHandler({UsersService.UserNonExistent.class})
public void handleUserNonExistentException() {
// Nothing to do
}
}
If the supplied user ID is invalid handleUserNonExistentException() method will be invoked and it will return a BAD REQUEST HTTP status code.
I am creating a REST service and I have the following API -
#PUT
#Path("/delete/{teamName}")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.TEXT_PLAIN)
public Response delete(#PathParam("teamName")String teamName) {
if (db.delete(teamName)) {
return Response.status(200).build();
}
return Response.status(400).build();
}
This API accepts a PathParam to delete a teamname. It is a PUT call.
My questions are -
Is it a good practice to use #PathParams in a PUT call?
What are the advantages and disadvantages?
It's OK to use PathParam in any kind of RESTful API resources handlers. But, PUT method is not suitable here since it breaks basic REST principles.
REST supposes that specific HTTP methods (like PUT, GET, DELETE, POST) correspond to specific actions that need be performed on the data.
For example, if you want to retrieve the data, you need to use GET, while DELETE is what you need to delete the data.
In your particular case I'd go with something like
DELETE /teams/{teamName}
I'd recommend you to acknowledge at least Use RESTful URLs and actions to have a better understanding of basic REST principles.
I'm using Jersey 2.19 to implement a REST API.
I'd like to know how I find out from the Jersey user guide or other specification how I'm supposed to know what the signature of my JAX-RS resource should be.
E.g. for a resource that handles POST requests I've experimented with the following different signatures using examples I've found.
public Response myResource()
public Response myResource(String param)
Both of these are valid in that they compile and run and the method is called under the right conditions.
Can anyone tell me where it is specified what the signatures should be and what the parameters mean? It seems like a straightforward question but I can't find the answer.
As you are saying its a POST request , so it should recieve some data from the Request. So you should expect something in Parameter.
public Response myResource(String param)
But the type of parameter should depend upon actually #Consumes annotation like :-
#Consumes(MediaType.APPLICATION_JSON) : This expects a JSONinput OR
#Consumes(MediaType.APPLICATION_XML) : This expects a XMLinput OR
#Consumes(MediaType.TEXT_PLAIN) : This expects a String plain text input
You annotate your Methods like described in the official documentation.
Also, do not forget to annotate the service-class with #Path
#Path("MyService")
public class MyService
{
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/User")
public List<User> getUser()
{
//Return all users
}
//Inserts new User in JSON Format
#Get
#Path("/User/UserId/{userid}")
public User getUserById(#PathParam("userid") String userid)
{
//Find User with ID in Database and return it
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public User getUserById(User user)
{
//add user to your Database or something
}
}
If you now want to get all users in json format you have to call:
http://ip-address/MyService/user
There is an exact answer to your question, but gird your loins. Because if the Jersey docs are overly vague these are in the extreme opposite direction: written by someone showing off their PhD in abstract algebra it looks to me.
The answer to everything is in the JAX-RS spec, of which Jersey is an implementation. You can download it here as PDF (after you sign away your soul)
The specific answer to how one of those methods is selected instead of the other, is too detailed for me to paste in here, but it's under section "3.7.2 Request Matching"
I won't even try to paste in the mathematical rules used to set up the list of potential methods to match a request, then select from among them. There's no chance of getting them formatted readably in SO.
For your more general questions, the section "3.3 Resource Methods" is much more accessible. Here are a few choice excerpts:
3.3 Resource Methods
...
JAX-RS defines a set of
request method designators for the common HTTP methods: #GET, #POST,
#PUT, #DELETE, #HEAD and #OPTIONS.
...
3.3.1 Visibility: Only public methods may be exposed as resource methods.
...
3.3.2 Parameters: Resource methods MUST have at most one entity parameter ...
3.3.3 Return Type: Resource methods MAY return void, Response, GenericEntity, or another Java type...
etc, etc.
I am newbie with RESTful services, I am trying to make a restful api with the Jersey framework and MongoDB, my question is : How can i search data in the URL.
e.g : "localhost:9999/home/users/find?id=12345", it will return the user with the id = 12345
How can we do that with Jersey ?
Thank's
You want to look into #PathParam and #QueryParam. You can find more about both of them here:
http://docs.oracle.com/cd/E19776-01/820-4867/6nga7f5np/index.html
In short, a path param is the bit between the '/', in your example this is "find". and the query param is id, which has a value of 12345.
You will then need to look this up in a database I assume to get your result to return.
You may want to look at an article I wrote a few years ago. I have a full stack MongoDb, Jersey, Jetty server user admin application at the following github [here](https://github.com/pmkent/angular-bootstrap-java-rest"Angular Bootstrap Java Rest")!
To use a query parameter in Jersey, you'll define it in the jersey Method signature like so:
#GET
#Path("home/users/find")
public Response myMethod(#QueryParam("id") int id) {
// utilizes the id specified in the url parameter "id"
User user = someMongoMethodToFindById(id);
}
Once you harvest the id correctly, you can then query your MongoDB however you'd like based on that passed-by-reference id.
In Jersey, this method is often wrapped in a class in which all related Jersey Resources can be organized. My examples given utilize the Jersey Annotation style.
#Path("home/users")
public class UserResources {
#Path("find")
public Response myMethod(#QueryParam("id")) {
...
}
}
I have a Spring MVC controller which is servicing GET requests, to perform a search.
These requests have many optional parameters which may be passed on the query string.
For example:
#Data
public class SimpleSearchRequest implements SearchRequest {
private String term;
private List<Status> stati;
#JsonDeserialize(using=DateRangeDeserializer.class)
private Range<DateTime> dateRange;
}
If I were using a POST or PUT for this, I could nicely marshall the inbound request using a #RequestBody. However, because I'm using a GET, this doesn't seem to fit.
Instead, it seems I'm required to list all the possible parameters on the method signature as #RequestParam(required=false).
Aside from leading to ugly method signatures, I'm also losing out on all sorts of OO goodness by not using classes here.
Attempting to use #RequestBody fails (understandably so), and as discussed here and here, using an actual request body on a GET is not desirable.
Is there a way to get Spring MVC to support marshalling multiple #RequestParam's to a strongly typed object on GET requests?
It seems the answer was to simply remove the annotation.
This worked:
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody List<Result> search(SearchRequest request) {}