PathParam Layer check REST - rest

First of all have a nice weekend for those who are! For the other good luck :)
I am creating an app using rest architecture.
I just have a simple question but I don't know how to explain it.
So let's take an example and maybe the question will come after.
Imagine you have a path element called Car. If I do a GET on it it returns the carInformation
So I would define:
#GET
#Path("/car/{carid}/display")
public Response getCar(#PathParam("carid")String carID)
If I define actions to perform on this car like open, close, start etc:
#POST
#Path("/car/{carid}/startup")
public Response startup(#PathParam("carid")String carID)
#POST
#Path("/car/{carid}/open")
public Response open(#PathParam("carid")String carID)
#POST
#Path("/car/{carid}/close")
public Response close(#PathParam("carid")String carID)
Is there a common check done at /car/{carid} like "is it my car?" "is it in the garage?" or do I have to implement it with abstraction for example between the process which will be called after
In fact I am not understanding the real goal of path param. Why don't do simply
#GET
#Path("/car/displayCar")
public Response getCar(#QueryParam("carid")String carID)
#POST
#Path("/car/startup")
public Response startup(String carID)
#POST
#Path("/car/{carid}/open")
public Response open(String carID)
#POST
#Path("/car/{carid}/close")
public Response close(String carID)
Thanks all for you answer in advance
Best regards
Geoffrey MUSELLI

There are a lot of ways to go at this, both REST and RPC - and I'm not here to say which is better (you need to evaluate which would be easier/better/etc for the consumers of your API [IMO]). For this I am going to go at it using a REST approach.
For displaying a single car's info there is no need for an endpoint ending in 'display'. A GET request to /car/{car id} is sufficient. That document can have things like the car's current state (open, closed, running, exploded, etc . . .) The GET is your action, the /car/{car id} is your thing, and the document it returns (and excepts via POST or PUT are the protocol of your API)

Related

In Spring's rest controller (marked with #RestController), functions can return both model objects and a ResponseEntity object, which is better?

As a Spring Boot noob, I just know that in the controller class, its public functions can return both model objects and ResponseEntity object. Something like
public List<Book> getBooks() {}
or
public ResponseEntity<Book> getBooks() {}
But my question is which is better when there are multiple choices?
Basically, you have control over the HTTP response status if you use ResponseEntity, in addition to the content of the object itself.
public ResponseEntity<Object> getObject() {
return new ResponseEntity<Object>(object, Httpstatus.OK);
}
For example, if you need to validate some data from the request before executing any action and you want to let your client know what happened through the HTTP status code you can choose between different options.
HttpStatus.CONFLICT
HttpStatus.CREATED
Here you can take a look on the different status codes:
HTTP Status Codes
Just to shed more light on what #lbpeppers has mentioned. Using a ResponseEntity has many advantages.
1. The client need not look into the body of the message if the status code is something like 400 or 404, which is quite helpful
2. In some cases the client is not interested in the body. All it needs is a status of the operation
3. There are a lot of handy methods like is1xxInformational, is2xxSuccessful, is3xxRedirection, is4xxClientError, is5xxServerError in HttpStatus calss which can be used like
response.getStatusCode().is2xxSuccessful()

Best practice for filtering results from a RESTful API call?

I'm defining a RESTful API for a TV broadcaster, specifically what the path should look like when asking for a subset of data. For example if I wanted to get the whole content for a particular channel, language on that channel between a specific date, how would I filter by date? The path below seems too long:
endpoint.com/content/channels/{channel_name}/language/french/from/20160701/to/20160801
An alternative I saw is to 'treat the search as a resource' and POST the date range filters to it in the request body, as mentioned here on SO: (How to design RESTful search/filtering?)
Any thoughts?
I will suggest you use #QueryParam annotation to filter your resources by getting it from URI.
To filter the resource you can use an URI like
/channel_name?language=french&from=20160701&to=20160801
Using JAX-RS you then can access the these values:
#GET
#Path("/channel_name")
List<Content> getContent(#QueryParam("language")String lang,
#QueryParam("from")Long from,
#QueryParam("to")Long to) {
// your logic
}
Of course you need to take care of exceptions and the repsonse including status codes in this case.
I also work for a TV Broadcaster and the approach we have taken is to post the search criteria through a resource. Much easier to handle and doesn't create an endless path.
Interface :
#POST
#Path("/lookup")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
List<Content> getContent(CriteriaSearch cr);
Implementation :
#Override
#Public
public List<ContentInfo> getContent(CriteriaSearch searchCriteria) {
List<ContentInfo> contentInfos = contentManager.lookupContent(searchCriteria);
...

Protect REST URL with same path and different http methods

I have a situation that I need some assistance with. I have four REST URL with same path and different http methods
/api/users/** GET,POST,PUT,DELETE
I want to use Shiro to protoct the PUP, POST, DELETE and keep GET is anonymous. I configured the following URLs but with out luck
/api/users/** =rest[user:update,user:delete,user:create]
/api/users/** =anon
Maybe you could do something like this:
/api/users/**=rest[user]
Then, it kind of depends on how you are creating the REST APIs. With a JAX-RS implementation, like Jersey for example, you could do the following:
#Path("/api/users")
public class SomeResource {
#RequiresPermissions("user:read")
#GET
public Response getResource() {..}
#RequiresPermissions("user:create")
#PUT
public Response putResource() {..}
#RequiresPermissions("user:update")
#POST
public Response postResource() {..}
#RequiresPermissions("user:delete")
#DELETE
public Response deleteResource() {..}
}
This is assuming that you are going with the Annotations based authorization. You could also use the SecurityUtils.getSubject() mechanism.

RESTful resource with an expensive property

I have a resource /messages.
In my java code, the Message interface looks like this:
interface Message {
public int getID();
public int getPostingUserID();
public String getText();
public int getRelevance();
}
For example, /messages/7 will give the following:
{ id: 7, postingUserID: 102, text: "tabs are better!", relevance: 10.3 }
Unfortunately, getRelevance() is quite expensive to calculate on-the-fly, and is only needed for perhaps a tenth of the queries. I don't want to calculate it when I don't need it.
So, I can see a few options:
/messages/7?includeRelevance=true to tell it to calculate the relevance, otherwise don't include it in the response
/messages/7/relevance as a separate request, and calculate it then
/relevances?forMessageID=7 as a separate request, and calculate it then
Which option is the most RESTful?
Thanks!
I would tend to go for /messages/7/relevance in this situation, and I'd make sure that the document returned when fetching /messages/7 includes a URL to the relevant relevance resource (for HATEOAS discoverability, of course).
The most RESTful way to do this (I believe, and could definitely be wrong) is to define 2 different media-types.
The client can request a specific one with the Accept: header, and you could default to the minimal one.

Complex (non string) return type for Jersey REST method

I'm having trouble setting something up that I'm pretty sure /should/ be easy, so I thought I'd throw it to the crowd. I can't seem to find what I'm looking for elsewhere on the web or on SE.
I am simplifying my project of course, but basically I have a JAX-WS annontated Jersey resource class that looks something like this:
#Path("myresource")
public class MyResource {
#Autowired
MyComplexObjectDAO daoInstance;
#Path("findObject/{id}")
#GET
public MyComplexObject findObject( #PathParam(value="id") String id ) {
return daoInstance.findObject( id );
}
#Path("saveObject")
#PUT
public MyComplexObject saveObject( MyComplexObject objectToSave ) {
MyComplexObject savedObject = daoInstance.saveObject( objectToSave );
return savedObject;
}
}
So you can see I'm autowiring a DAO object using spring, and then I use the DAO methods in the REST handlers.
The 'findObject' call seems to work fine - so far it works exactly as I expect it to.
The 'saveObject' call is not working the way I want and that's what I need some advice on.
You can see that I'm trying to directly take an instance of my complex object as a parameter to the REST method. Additionally I would like to return an instance of the complex object after it's been saved.
I put together some 'client' code for testing this out.
#Test
public void saveTest() {
WebResource wsClient = createWebServiceClient();
MyComplexObject unsavedInstance = createMyComplexObject();
MyComplexObject savedInstance =
wsClient
.path("saveObject")
.accept(MediaType.APPLICATION_XML)
.put(MyComplexObject.class, unsavedInstance);
assertNotNull(savedIntent);
}
Which is returning the following error:
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:8081/rest/myresource/save returned a response status of 400 Bad Request
I don't see why this isn't working and I think I've tried just about everything I can think of. Any help or direction would be very much appreciated.
Thanks so much!
I see that you call the accept() method in your test client (which means that a "Accept:" header is added to the request, indicating the server what type of representation you would like). However, you don't call the type() method to add a "Content-type:" header and inform the server that you are sending XML data. See http://jersey.java.net/nonav/documentation/latest/client-api.html#d4e644 for examples.
Side remark: your URLs are not RESTful - you should avoid verbs in your path:
So, instead of:
/api/findObject/{id}
/api/saveObject
You should use:
/api/objects/{id}
/api/objects
Last note: to create an object on calling /api/objects, you should do a POST and not a PUT to adhere to REST best practices and widely adopted patterns.
switching to the 'concrete class' solution I alluded to in my earlier comment is what fixed things up for me.