How bad is it to use #POST to retrieve data? - java

I am currently using a #POST web service to retrieve data.
My idea, at the beginning, was to pass a map of parameters. Then my function, on the server side, would take care of reading the needed parameters in the map and return the response.
This is to prevent having a big number of function almost identical on the server side.
But if I understood correctly, #POST should be use for creation of content.
So my question: Is it a big programming mistake to use #POST for data retrieval?
Is it better to create 1 web service per use case, even if it is a lot?
Thanks.
Romain.

POST is used to say that you are submitting data.
GET requests can be bookmarked, POST can't. Before there were single page web appliations we used post-redirect-get to accepta data submission and display a bookmakable page.
If you use POST to retrieve data then web-caching doesn't work, because the caching code doesn't cache POSTS, it expects POST to mean it needs to invalidate its cache. If you split your services out use-case-wise and use GET then you can have something like Squid cache the responses.
You may not need to implement caching right now, but it would be good to keep the option open. Making your services act in a compliant way means you can get leverage from existing tools and infrastructure (which is a selling point of REST).

doGet();
Called by the server (via the service method) to allow a servlet to handle a GET request.
doPost()
Called by the server (via the service method) to allow a servlet to handle a POST request.
No issues with them.Both will handle your request.

Related

Use response from a restful webservice endpoint call to be used later on in some other webservice endPoint call

I want response from one webservice call to be used later on by some other webservice call. How do I implement the code flow for it. Do I have to maintain a session?
I am creating the restful webservices using Spring,java
If user 1 calls an endPoint /getUserRecord and 1 minute later calls /checkUserRecord which uses data from the first call, how to handle it since user 2 can call /getUserRecord before user 1 calls /checkUserRecord
I am using Spring java to create RESTFul webservices.
Thanks,
Arpit
technically you can pass UserRecord from get to check.
GET /userrecords/ --> return the one or more record
POST /checkUserRecord with the record as you want to check as request body.
But I strongly advise you to not do this. Data provided by client are unreliable and cannot be trust by your backend code. What if some javascript has altered the original data ? Besides, what if you have a list of data or heterogenous payload to pass back and forth, it would end up to a complete mess of payload exchanges from client and server.
So as Veselin Davidov said, you should probably stick with clean stateless REST paradigm and rely on identifier:
so
GET /userrecords/ --> [ { "id": 1, "data":"myrecorddata"}, ...]
GET /checkUserRecord/{id} like /checkUserRecord/1
and yes, you will have to make two calls to the database. If your concern is performance, you can set some caching mecanism as piy26 points out, but caching could lead you to other issues (how to define a proper and reliable caching strategy ?).
Unless you manage a tremendous amount of data, I think you should first focus on providing a clear, maintainable and safely usable REST API with stateless design.
If you are using Spring Boot, it provides a way to enable caching on your Repository object which is what you are trying to solve.
#EnableCaching
org.springframework.cache.annotation.EnableCaching
You can use UserID as a hash attribute while creating your key so that response from different users remains unique.

Why does spring-social's ConnectController start the OAuth 2 "dance" with a POST?

I'm trying to make an app that connects to Fitbit via OAuth2 using spring-social. I've had some troubles with this but I think I'm figuring things out. I notice that the OAuth process is initiated by making a POST to the ConnectController. Why is this done with a POST rather than a GET? I'd like to make it so that I can drop a link into a chatroom that the user can click to authorize my app to use their Fitbit information, which means that I'd like to start things off with a GET. Is there a reason why this isn't done? If I were to make changes to this effect (by subclassing ConnectController) would I run into technical/security problems?
There are 2 reasons:
The primary reason is that GET requests are expected to perform operations that are both safe and idempotent. But as a result of that request, you may (in the case of OAuth 1.0(a)) end up obtaining and possibly storing a request token as well as initializing the OAuth dance with the provider. This is not considered "safe" in the terms of a safe request. Moreover, it may or may not be idempotent, as repeating the request may result in a different behavior (depending the the provider's implementation of OAuth). While this may not apply to OAuth 2, it needed to be consistent between OAuth 1 and OAuth 2.
The /connect/{provider} path represents a single resource. There are only so many HTTP verbs to choose from without resorting to putting verbs into the path. The GET method for that path is already assigned to the request to fetch connection status for that provider (an operation which is both safe and idempotent).
Even so, I've encountered the use-case you're asking about. What I've done when I feel the need to have a link that kicks off the OAuth flow is to have a form that POSTs to /connect/{provider} and have some Javascript that submits the form for me, either as the result of a direct link (if the link is on a page in the app) or as the result of page load (if the link is to be given in an email or chatroom).
You're also certainly welcome to override ConnectController's behavior or even write your own implementation of the controller to meet your needs, even if they violate the reasoning behind why ConnectController is implementation the way it is.

Receiving and processing 3rd party Posts in Tapestry app

The goal of my app is to create a leaderboard for a competition. To add to one's score, you just have to write something in hipchat (I already have a listener in hipchat that attempts to make a post to my Tapestry app).
I am running into lots of trouble around accepting and handling a 3rd party POST to my Tapestry app. All the documentation I can find deals with internal requests.
Does anyone have any experience in setting up a way to receive a 3rd party post, handle it and make actions with the information? Any help would be great!
Tapestry's native POST handling is intended for handling HTML form submits and is not a good match for machine initiated REST requests. Consequently, I'd handle it as a REST resource request, which JAX-WS is meant for. I assume you mean Tapestry 5 and if so, it's pretty to get started with Tynamo's tapestry-resteasy module (for disclosure, I'm one of the maintainers). If you are new to JAX-WS, you may want to read an overview about it (the link is for Jersey, the reference implementation but the annotations work the same way regardless of implementation). In principle, you'd implement a (POJO+annotations) resource class and an operation with something like this:
#POST
#Produces({"application/json"})
public Response scorePoints(User user, long score)
{
leaderboardService.add(user, score);
return Response.ok().build();
}
On the client side, you'd just pass in the user ID and Tapestry's type coercion would handle the rest (assuming User is a known entity to Tapestry). Of course, you could just use primitive data types on both sides as well.

Several logins in RESTFUL API

We are designing a RESTFUL API that needs to support several login services.
Custom login: ptgapi/v1/clients/{clientId}/users?mode=custom
FB login: ptgapi/v1/clients/{clientId}/users?mode=facebook
Twitter login: ptgapi/v1/clients/{clientId}/users?mode=twitter
LinkedIn login: ptgapi/v1/clients/{clientId}/users?mode=linkedin
Create user: ptgapi/v1/clients/{clientId}/users
We have an Spring Integration layer in top of the services, so in based of the provided path, one of the services will need to be activated.
The idea would be to have a router that catches the inbound-gateway input and redirect the flow based on the payload value.
<int-http:inbound-gateway id="v1.login.inbound.gateway" path="/ptgapi/{apiVersion}/clients/{clientId}/users" .../>
But here 'create user' has the same routing process than the other ones...and I think this is a bad smell.
Is a better approach to obtain it with a better separation of concerns?
Thanks!
Services may have the same path/route but they are identified by the operation. In REST you will have same path for services but depending on the kind of operation you are doing the HTTP method will be different. You can differentiate your login and create services by using POST and PUT HTTP methods.
Personally speaking, I believe PUT is a better choice because PUT gives more control such as :
Do you name your URL objects you create explicitly, or let the server decide? If you name them then use PUT. If you let the server decide then use POST.
PUT is idempotent, so if you PUT an object twice, it has no effect. This is a nice property, so I would use PUT when possible.
You can update or create a resource with PUT with the same object URL
More on PUT versus POST
PUT implies putting a resource - completely replacing whatever is available at the given URL with a different thing. By definition, a PUT is idempotent. Do it as many times as you like, and the result is the same. x=5 is idempotent. You can PUT a resource whether it previously exists, or not (eg, to Create, or to Update)!
POST updates a resource, adds a subsidiary resource, or causes a change. A POST is not idempotent, in the way that x++ is not idempotent.
For the user CRUD you should have a route like ptgapi/v1/clients/{clientId}/users and use the HTTP methods as they are supposed to: GET for returning the user, PUT for creating the user, POST for updating the user and DELETE to remove it.
The login operation is not a user entity operation per se. You should have another route, just like ptgapi/v1/clients/login and pass the login parameters via POST (encrypted preferably).
Create user is an action so maybe you can define a new route like
Create user: ptgapi/v1/clients/{clientId}/users/new
or something like this.

Preferred method for REST-style URL's?

I am creating a web application that incorporates REST-style services and I wanted some clarification as to the preferred (standard) method of how the POST requests should be accepted by my Java server side:
Method 1:
http://localhost:8080/services/processser/uid/{uidvalue}/eid/{eidvalue}
Method 2:
http://localhost:8080/services/processuser
{uid:"",eid:""} - this would be sent as JSON in the post body
Both methods would use the "application/json" content-type, but are there advantages, disadvantages to each method. One disadvantage to method 2, I can immediately think of is that the JSON data, would need to be mapped to a Java Object, thus creating a Java object any time any user access the "processuser" servlet api. Your input is much appreciated.
In this particular instance, the data would be used to query the database, to return a json response back to the client.
I think we need to go back a little from your question. Your path segment starts with:
/services/processuser
This is a mistake. The URI should identify a resource, not an operation. This may not be always possible, but it's something you should strive for.
In this case, you seem to identify your user with a uid and an eid (whatever those are). You could build paths such as a user is referred to by /user/<uid>/<eid>, /user/<uid>-<eid> (if you must /user/uid/<uid>/eid/<eid>); if eid is a specialization, and not on equal footing with uid, then /user/<uid>;eid=<eid> would be more appropriate.
You would create new users by posting to /user/ or /user/<uid>/<eid> if you knew the identifiers in advance, deleting users by using DELETE on /user/<uid>/<eid> and change state by using PUT on /user/<uid>/<eid>.
So to answer your question, you should use PUT on /user/<uid>/<eid> if "processuser" aims to change the state of the user with data you provide. Otherwise, the mapping to the REST model is not so clean, possibly the best option would be to define a resource /user/process/<uid>/<eid> and POST there with all the data, but a POST to /user/process with all the data would be more or less the same, since we're already in RPC-like camp.
For POST requests, Method 2 is usually preferred, although often the resource name will be pluralized, so that you actually post to:
http://localhost:8080/services/processusers
This is for creating new records, however.
It looks like you're really using what most RESTful services would use a GET request for (retrieving a record), in which case, Method 1 is preferred.
Edit:
I realize I didn't source my answer, so consider the standards set by Rails. You may or may not agree that it is a valid standard.

Categories

Resources