I have a request that creates a payment. A payment has a form of payment that can be credit card or ticket.
When I return the HTTP response I would like to not have to verify what form of payment was used. The way I did this was by having my model class know how to create the form of payment response.
My question is: Is code smells considered the domain class know how to create the response class of an HTTP request? If yes, what's the best way to handle with this situation?
Example for a better understanding of the question:
class Payment {
private BigDecimal value;
private PaymentMethod method;
}
abstract class PaymentMethod {
public abstract String getResponse();
}
class Card extends PaymentMethod {
//attributes
public Response getResponse() {
return new CardResponse();
}
}
class Ticket extends PaymentMethod {
//attributes
public Response getResponse() {
return new TicketResponse();
}
}
Is code smells considered the domain class know how to create the response class of an HTTP request?
Probably yes. It will be harder to test as your unit tests will now need to be aware of HTTP. It also limits the usability of your domain class. If you end up needing to use another endpoint technology other than HTTP (SOAP, web sockets, etc.) you will have a problem. If you end up returning a redirect response then it spreads your URL mapping throughout your application making it harder to keep a handle on that.
Now, if I were to inherit your code base I wouldn't necessarily jump in and change it right away. I wouldn't say it is a fatal flaw but it isn't something I would do in a new project.
If yes, what's the best way to handle with this situation?
This question is probably overly broad and you haven't given a lot of details so here is a generic answer.
The simplest solution I've seen is to have a layer on the outermost of your application whose job is to convert from HTTP to domain logic and back. These types are often called controllers but that word is used so much I prefer the word endpoints. Forgive my pseudocode here, it's been a while since I've used the Java HTTP types.
// Crude example
public class PaymentEndpoint {
public Response handlePayment(HttpRequest request) {
if (request.getContentType() == "application/json") {
Ticket ticket = deserializeTicket(request);
Payment payment = this.paymentService.processTicket(ticket);
return serializeTicketPayment(Payment);
} else if (request.getContentType() == "application/x-www-form-urlencoded") {
CCInfo ccInfo = getCcInfoFromForm(request);
Payment payment = this.paymentService.processPayment(ccInfo);
return serializeCcPayment(payment);
}
}
}
However, that can lead to a lot of boilerplate code. Most HTTP libraries now have methods for doing the domain->HTTP conversion in filters. For example, JAX-RS has annotations you can use to specify which method to use if the content type is X and which to use if the content type is Y and annotations to populate method parameters from form fields or JSON content.
JAX-RS also allows you to return POJOs from your endpoints and it will handle the conversion to a response in its own logic. For example, if you return an object, it will use Jackson to serialize the object to JSON and set the response status to 200. If you return void then it will set the response status to 204.
// Crude example
public class PaymentEndpoint {
#Consumes("application/x-www-form-urlencoded")
public Payment handleCcPayment(#FormParam("name") String name) {
CCInfo ccInfo = new CCInfo(name);
return this.paymentService.processPayment(ccInfo);
}
#Consumes("application/json")
public Payment handleTicketPayment(Ticket ticket) {
return this.paymentService.processTicket(ticket);
}
}
Now, I'm not entirely sure what your asking, but it almost seems like you might need to serialize a ticket payment to HTTP very differently than the way you would serialize a credit card payment to HTTP. If they are simply different JSON objects you can use the example above. However, if you need to set certain HTTP headers in one response and not the other then you might have to do something more fancy.
You could just shove the logic in the endpoint:
if (payment.getPaymentMethod() instanceof Card) {
//Set special HTTP headers
}
However, if you have several endpoints that have to repeat this same logic then it can quickly become boilerplate code. Then you usually extend your filter layer to control the serialization. For example, in JAX-RS there is the concept of a MessageBodyWriter. You can give the JAX-RS framework a custom message body writer which tells it how to convert a card payment into an HTTP response. Although if you were just setting HTTP headers you could probably use a ContainerResponseFilter instead.
Related
at work we building an web application with java spring backend and vue frontend.
At the moment we uses 2 or 3 http response code to pass errors between frontend and backend.
If you call and endpoint with wrong parameters, you'll get an BAD_REQUEST. If some exception was thrown in the backend (which isn't related with the parameters) the backend returns an INTERNAL_SERVER_ERROR and if you pass some ids which aren't in the database the backend returns an NOT_FOUND.
This method has multiple problems:
we have no structure in error case which we can use to pass information to the user (frontend)
we want to indicate problems to the user, which can't be classified by HTTP response codes. For example if an external service isn't available, we want to pass the service name to the frontend. But I don't know if "SERVICE_UNAVAILABLE" fits here...
I found this already: https://www.baeldung.com/spring-response-status-exception
We could use the message field to pass detailed information about an error (specific error json in message field).
Is this a good idea?
Opinions?
T
You can certainly pass information back in this field but using ResponseStatusExceptions. Depending on how much information the frontend needs (e.g. if it's just surfacing a user friendly message to the user) this may be enough for your needs.
Another approach, if you want to use a custom object in the response (esp. per exception/response code), is using #ControllerAdvice and extending ResponseEntityExceptionHandler.
e.g. say you have a custom exception ExternalServiceUnavailableException which had some underlying ServiceInformation you could retrieve from it. Then you could do something like
public class ServiceInformation {
private final String name;
private final String status;
private final String statusMessage;
//snip
}
#ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler({ ExternalServiceUnavailableException.class })
public ResponseEntity<Object> handleExternalServiceUnavailable(ExternalServiceUnavailableException ex, WebRequest request) {
final ServiceInformation si = ex.getServiceInformation();
return ResponseEntity
.status(503) // or whatever code you want
.body(si); // or map to some other object/format
// or use the constructor to supply headers etc.
}
}
When you throw a ExternalServiceUnavailableException this would result in a response body like
{
"name": "my-external-service",
"status": "timeout",
"statusMessage": "Service timed out after 30 seconds"
}
A more complete example of this can be found in the below article where the same custom error object is used for each of the exceptions of consequence as well as a default handler.
https://www.baeldung.com/exception-handling-for-rest-with-spring
This makes it easier for the frontend to interpret (as does your proposed approach) since there is only a single format to expect and parse, but you are free to return different response shapes per exception.
Edit: it's worth remembering that there are also response codes 502 (bad gateway) and 504 (gateway timeout) which can be used to indicate an external service is either unavailable or timing out. If these are appropriate you could just use appropriate ResponseStatusExceptions with a message set to include the service name (or other info). As above, it depends on what you need/want the fronted to receive.
I am about to start my first real project for work (new grad), and I was tasked with creating an internal address book for the company (displaying name, phone extension number, email etc).
My mentor told me that I need to pull the address data from Active Directory.
He also told me that I need to use Angular 2 for the front end, and Spring for the backend. I still need to learn these frameworks, but he realizes this which is precisely why he gave me this task.
However, I am struggling to understand the flow of data between the frameworks.
This is what I am thinking so far http://imgur.com/a/xiH6m.
If someone could please explain what is right/wrong with the diagram and perhaps explain how the data would flow in such a project. I would prefer to bother my mentor with more specific questions.
Just create a REST service with Spring that returns the data as JSON. You can use a simple POJO on the server side, and the converter for Spring should convert it to JSON. Maybe something like
#RestController
public class EmployeesController {
#Autowired
private LdapService service;
#RequestMapping(value = "/employees/{empId}")
public Employee getEmployee(#PathVariable("empId") Long empId) {
Employee emp = ldapService.getEmployee(empId);
return emp;
}
}
With Spring, it should convert the Employee object to JSON on the outbound response (given you have the JSON converter configured).
In Angular, just make a simple Http request to the endpoint, and you will get back JSON, for which you can convert it to an Employee object on the client side. Maybe something like
class Employee {
// employee properties
}
#Injectable()
class EmployeeService {
constructor(private http: Http) {}
getEmployee(empId: number): Observable<Employee> {
return this.http.get(`${empBaseUrl}/${empId}`)
.map(res => res.json() as Employee)
}
}
Here, in the service, you make the Http request to the employee endpoint on the server, and get the result back as JSON, for which you convert it to an object with res.json() and cast it to Employee
That's pretty much it.
Your "Converts to useful format" will not happen on its own. You need a Controller layer there. REST Controller to be precise.
AngularJS 2 is built to work easily with REST. You can use Spring MVC to create REST Controllers which can generate JSON Response.
for Example you can have an Endpoint
GET /contacts/data
which will return
[
{"name":"ABC",
"email":"someone#abc.com",
"telephone":"0101010101"
},
...
]
The following Spring documentation will be a good starting point eventhough it talks about Angularjs 1.
I see a lot of Jersey-based web services consisting of 1+ WebResources that have 1+ endpoints/methods like so:
package com.myws.fizz;
public class FizzResource {
#GET
#Path("/fizz/{id}")
public Response getFizzById(#PathParam("id") Long id) {
// ...etc.
}
#GET
#Path("/fizz")
public Fizz getFizzByFoo(Foo foo) {
// ...etc.
}
}
package com.myws.buzz;
public class BuzzResource {
#POST
#Path("/buzz")
public Response createBuzz(Buzz buzz) {
// ...etc.
}
}
I'm confused with what Jersey considers a "resource". Is there a relationship between a "resource" and a database? A table? A POJO?
When do you return a Response vs. a POJO? Look at my 2 getFizz methods above. When do I return a Fizz and when do I return a Response?
The term "Resource" isn't so much just a Jersey term, as it is a REST term. When dealing with REST, we have Resources and Representations. A resource can be anything, and in this context, it is some object located on the server, with a URL location. When a client requests for a resource, we send back a representation of it. You ask:
Is there a relationship between a "resource" and a database? A table? A POJO?
It could be a database (that's a thing). And we could simply represent it as a JSON object with the name of the database. Also it could be a table (that's a thing). And we could represent it as a JSON object with the name and column names. It could be a row in a table, and we could represent that with a JSON object with the column names as the keys and the row values as the JSON values. It could be a web page, an image, whatever. So hopefully you get the point that a resource can be anything. What we send back is its representation.
But the term resource is not just limited to returning something to a client request. The client could also send us a representation of a resource, to say create a new resource (POST) or change an existing resource (PUT). The client may send us a JSON representation of a row (resource) in our database.
When do you return a Response vs. a POJO? Look at my 2 getFizz methods above. When do I return a Fizz and when do I return a Response?
Returning Response allows you to fine tune the Response. When the client make a request, they always get back a response. Responses have headers, and entity bodies. When the return type of the resource method is Fizz, you are saying the entity body type will be a Fizz type. When the method returns, what actually happens is that the Fizz object isn't directly returned to the requesting client, all by itself. Behind the scenes, it gets wrapped in a Response that get's sent back to the client. The framework will set the headers it feels appropriate.
So whether we decide to return a Response or Fizz, it will get wrapped in a Response. And like I said, when we return a Response, it allows us to fine tune the Response, adding our own headers, status codes and such. For example, say someone make a POST. You could do something like
#POST
#Path("/buzz")
#Produces(...)
public Response createBuzz(Buzz buzz, #Context UriInfo uriInfo) {
int buzzID = // create buzz and get the resource id
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path(Integer.toString(buzzId)); // concatenate the id.
return Response.created(builder.build()).build();
}
Basically what this does is create the resource, say in the database, and we get a return id. We can use the id to concatenate to the URI to the id, this will be the new resource location. In terms of the Response, .created(...) is saying that the status code should be 201 Created, and the value we pass to the created method is the location of the newly created resource. This location will be set as the Location header in the response. So lets say that the path to the POST request is http://blah.com/buzz. What we would send back is http://blah.com/buzz/100, where 100 is the buzzId, and this complete URL is how we will access the buzz resource say with a GET requesst to a resource method annotated with say #GET #PATH("/buzz/{id}")
In terms of a GET, with a Response, we could do
Fizz newFizz = fizzService.getFizz();
return Response.ok(newFizz).build(); // sends the Fizz as the entity body
This is really not so much different than just returning the newFizz from the method, because we aren't doing anything special with the Response. We're just saying the status code should be 200 OK and attaching the entity body. This is what normally happens with a successful GET request. So if we just return the Fizz, instead of a Response, in the case of a successful GET, the framework will implicitly attach a 200 OK status.
Personally, I prefer to return Responses, because of the fine tuning factor.
I've create a simple test case with Jackson 1.9 and Spring 3. My goal was to test how easy was to use both of them to generate JSON results. My problem is that I get an error 406
So far, it seems that you only need to configure Spring and the code is really straightforward . My Spring configuration file is just:
<context:component-scan base-package="com.goldengecko" />
<context:annotation-config/>
<mvc:annotation-driven />
And my controller:
#Controller
public class TestsController
{
#RequestMapping(value = "/tests", method=RequestMethod.GET)
public #ResponseBody Item getBooks() {
return new Item();
}
}
The Item class is just:
public class Item {
private String name;
public Item() {
name = "Test name";
}
private String getName() {
return name;
}
private void setName( String name ) {
this.name = name;
}
}
I made sure I added the jackson-core-asl.jar and jackson-mapper-asl.jar.
From everything I read, it's just that: you don't seem to need to worry about setting a content-accepted in the request, just open a normal Chrome browser and request that service.
That's where I get a 406.
I created a simple jQuery getJSON call, with the same result.
Do you know what can be wrong? So far there are few things to fail: the code seems to be the right approach and the Jackson files required by Spring are there.
Per section 10.4.7 at http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html:
The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.
Unless it was a HEAD request, the response SHOULD include an entity containing a list of available entity characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. Depending upon the format and the capabilities of the user agent, selection of the most appropriate choice MAY be performed automatically. However, this specification does not define any standard for such automatic selection.
Note: HTTP/1.1 servers are allowed to return responses which are not acceptable according to the accept headers sent in the request. In some cases, this may even be preferable to sending a 406 response. User agents are encouraged to inspect the headers of an incoming response to determine if it is acceptable.
If the response could be unacceptable, a user agent SHOULD temporarily stop receipt of more data and query the user for a decision on further actions.
So it sounds like perhaps you do need to set the acceptable content types on the receiving side.
I am trying to implement a request/response client. Here is the basic implementation for it.
Class Request
{
prepareRequest1();
prepareRequest2();
}
Class Response
{
processResponse1();
processResponse2();
}
Class Client
{
connect();
sendRequest();
}
myrequest = new Request();
client = new Client (myserver);
my $rawResponse1 = client.sendRequest (myrequest.prepareRequest1());
myresponse = new Response();
myresponse.processResponse1 ($rawResponse1);
I have three classes namely - Request, Response and Client. Request class contains a function specific to a request. These request are the XML requests. There XML request does not have anything in common except few initial tags (e.g. sessionid etc). All other XML parameters are specific to the type of request. So, Currently I am handing it by creating a separate function for each request. I understand that it has a scalability issue, but please suggest me some other best approach I can apply here.
Similar to the request, the response to each request require a specific treatment. so I have a separate function specific to each type of response I am expecting. Generally you can assume that there is a 1:1 mapping between request and response.
Last is the Client class which hands for connection.
I have almost 50+ such request and response, and I am planning to implement with this approach. As I am in initial stage of development, please suggest me some improvement/best practices to implement such request/response.
Its best if you keep the mapping of the request and response outside of your code. Easier to manage. Keep an xml config file that stores the class names of your request and response tied to a particular type of xml message. You can then obtain the class names and go to that class to process your request and response. Its best to have separate classes to handles these messages rather than separate methods. Thats more scalable. Ensure you have interface for all your request classes and the same for your response classes. This will make it easy to swap your request responses classes easily by modifying the xml config file..
Hope you got it :)