I have a class Response which contains a HTTP response with a HTTP status code like 200 or 404 and few other things like a view name and a domain object. But lets focus on the status code. I could use a single class and pass the status as a parameter:
public class Response {
private int status;
public Response(int status) {
this.status = status;
}
}
// in a handler method:
return new Response(HttpStatus.OK);
The other way would be to create a new class for every status code (41 status codes in HTTP 1.1). Like this:
public class Ok extends Response {
public Ok() {
super(HttpStatus.OK);
}
}
// in a handler method:
return new Ok();
public class Created extends Response {
public Created() {
super(HttpStatus.CREATED);
}
}
// in a handler method:
return new Created();
In reality there will be usually more parameters like the view name and the domain object, like this new Response(HttpStatus.OK, "customer", customer) respective new Ok("customer", customer).
my recommendation
1) if there is no behavior associated with each status code then there is no need for new abstractions.
2) use enums for constants instead of int
The "pure" way would be to have a type for each distinct value, but in practice this may be overkill.
Generally speaking, consider whether:
There is any unique processing (which would lend itself to classes)
Whether there could be a hierarchy between the entities (e.g., statuses representing success and statuses representing errors).
In my experience, if there are hierarchies in the domain, they often end up in the code. You could save future refactoring by planning around that. For instance, error statuses may later also have things like error details tacked on.
My rule of thumb is to look at the specification in which the magic numbers appear. If they are each associated with a lot of details, that could indicate future problems if I merely keep them as ints, since I am essentially using a key to a more complex entity.
Also, when taking details from a fixed domain, an enum might be better than direct int.
Ask yourself - do you need different "types" for each status code? It could be useful if for example you want to use a specific type say OK as the parameter to some method. If not, I don't see any benefits of the second approach. Go for the first one.
I would keep the constructor simple. Something like:
public Response(int status)
public Response(int status, String reasonPhrase)
public Response(int status, Map<String,String> headers)
public Response(int status, String reasonPhrase, Map<String,String> headers)
Or, possibly, omit the last 2 and provide a setHeader(String, String)
Related
I'm writing an API Gateway that must route requests based on a MAC address. Example of endpoints:
/api/v2/device/AABBCCDDEEFF
/api/v2/device/AABBCCDDEEFF/metadata
/api/v2/device/search?deviceId=AABBCCDDEEFF
I've written a Custom Predicate Factory that extracts the MAC address, performs the necessary logic to determine what URL the MAC address should be routed to, then stores that information on the ServerWebExchange attributes.
public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config> {
// Fields/Constructors Omitted
private static final String IP_ATTRIBUTE = "assignedIp";
private static final String MAC_ATTRIBUTE = "mac";
#Override
public Predicate<ServerWebExchange> apply(Config config) {
return (ServerWebExchange exchange) -> {
String mac = exchange.getAttributes().get(MAC_ATTRIBUTE);
if(mac == null){
mac = extractMacAddress(exchange);
}
if(!exchange.getAttributes().contains(IP_ATTRIBUTE)){
exchange.getAttributes().put(IP_ATTRIBUTE, findAssignedIp(mac);
}
return config.getRouteIp().equals(exchange.getAttribute(IP_ATTRIBUTE));
});
}
// Config Class & utility methods omitted
}
NOTE: This implementation is greatly simplified for brevity
With this implementation I'm able to guarantee that the MAC is extracted only once and the logic determining what URL the request belongs to is performed only once. The first call to the predicate factory will extract and set that information on ServerWebExchange Attributes and any further calls to the predicate factory will detect those attributes and use them to determine if they match.
This works, but it isn't particularly neat. It would be much easier and simpler if I could somehow set the Exchange Attributes on every single request entering the gateway BEFORE the application attempts to match routes. Then the filter could be a simple predicate that checks for equality on the Exchange Attributes.
I've read through the documentation several times, but nothing seems to be possible. Filters are always scoped to a particular route and run only after a route matches. It might be possible to make the first route be another Predicate that executes the necessary code, sets the expected attributes and always returns false, but can I guarantee that this predicate is always run first? It seems like there should be support for this kind of use case, but I cannot for the life of me find a way that doesn't seem like a hack. Any ideas?
Use a WebFilter instead of a GatewayFilter or a GlobalFilter. They are applied only after the predicates chain. Whereas WebFilter works as an interceptor.
#Component
public class CustomRoutePredicateFactory implements WebFilter, Ordered {
private static final String IP_ATTRIBUTE = "assignedIp";
private static final String MAC_ATTRIBUTE = "mac";
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String mac = (String) exchange.getAttributes().computeIfAbsent(MAC_ATTRIBUTE, key -> extractMacAddress(exchange));
exchange.getAttributes().computeIfAbsent(IP_ATTRIBUTE, key -> findAssignedIp(mac));
return chain.filter(exchange);
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
I think your approach makes sense since you want it to run before filters.
Have you considered using a GlobalFilter with an order set on it? You can ensure it's always the first filter to run. You can also modify the URL in the ServerWebExchange by mutating the request and setting the GATEWAY_REQUEST_URL_ATTR attribute on the exchange.
Take a look at the PrefixPathGatewayFilterFactory for an example of how to change the URI being routed to.
You can set an order on the Global filter by implementing the org.springframework.core.Ordered interface.
That being said, it still feels a little like a hack but it's an alternative approach.
i think it may help you that overriding the class RoutePredicateHandlerMapping.
see: org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler
The question is regarding best practices with respect to REST APIs.
Example: I have a get API with a path-param as status.
/api/{status}
Now, in the code, the status is defined as an enum (Status). There can only be 3 (or some small finite) possible values of status.
public enum Status {
created,
completed,
cancelled
}
So, should I accept "status" as a string or as Enum type?
#Path("/api/{status}")
#GET
public Response get(#PathParam("status") String status) {}
// then I can check if it is a valid status
OR
#Path("/api/{status}")
#GET
public Response get(#PathParam("status") Status status) {}
// it will throw an exception if it is an invalid status
Also, I would like to know the best-practices with respect to query-params and JSON requests as well.
Using enums on API, brings better design. Reasons for it are same as why we use them in general. There is compatibility between enums in programming languages that have them, and OpenApi specification https://swagger.io/docs/specification/data-models/enums/ therefore there I see no good argument against them.
I am working on designing a common Service interface for atleast 5 concrete implementations. Now all these services require different types of inputs. I thought of creating a Param class to hold parameters, so that interface could remain common. but then, for some implementations, some of the fields will be unused. I also thought of using Map to hold my params, but that is also not good(casts and if-elses everywhere). Also, I thought of doing was to create a class with Static methods Service.responseAsPerFirstImplementation(p1, t1, i1) and such. But, this way is not good coding. Please suggest how I should design between Modular design, flexibility vs variability of parameters?
EDIT:
Is below the good way of doing it?
public class Client {
public static void main(String[] args) {
System.out.println(Services.response(new UserParam(1, new Date())));
System.out.println(Services.response(new PatternParam("core")));
}
}
I think the core of the question is if your parameters come from some "generic", unstructured sourcelike HTTP request parameters or command line arguments or some structured source - I would put a Swing form there as you know in advance which UI elements you have.
In case of "generic" parameters you have to convert these parameters into something your services can process. You can do this manually or with some library/framework. For instance, you can use annotations to describe how your HTTP request and its parameters map to your controllers/services/methods:
#RestController
#RequestMapping("/trainRun")
public class TrainRunController {
#RequestMapping(value = "/{year}/{month}/{day}/{trainNumber}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public TrainRun getTrainRun(#PathVariable Integer year, #PathVariable Integer month, #PathVariable Integer day,
#PathVariable String trainNumber) { ... }
}
Similarly with command-line parameters - you can use somethings like args4j to map CLI parameters into Java object first and then call your services appropriately.
Hope this helps.
I have to following endpoint structure in Jersey:
/objects/
/objects/:id
/objects/:id/:field
/objects/:id/:field/:subfield
The IDs I'm using have a very specific format, so I first check if the format is valid before making a request to the database.
Right now I have to put this code in each of the POST, PUT, GET, DELETE functions for each of the functions that has :id as a parameter. So this just means an early return.
if (!isIdValid(id)){
return Response.status(Response.StatusType.BAD_REQUEST)
.entity("The ID you've provided is invalid")
.build();
}
(In reality the error entity is an object containing more information about the error)
And then for each function using the :field or :subfield parameters the code is similar. This checking and error-handling behavior has to be copied every time. And when I start copy-pasting stuff, I start thinking: there should be a better way?
I would like to place the :id checking code at the the /objects/:id level, and then all further nested levels are assumed have a valid ID. The same for the other parameters further nesting down.
I've been looking into using subresource locators, but then you create a function returning a new instance of the subresource. I can't put a conditional return of a Response-object at that level for if the validation fails.
#Path("{id}")
function Class<ObjectFieldResource> getObjectById(#PathParam("id") String id){
return ObjectFieldResource.class;
}
I could start throwing exceptions, but I would rather avoid that, since I don't really consider invalid input to be an exception.
How would such a structure best be implemented? I've looked at bean validation but that doesn't seem to allow me to define validation for my specific format + custom error responses.
Am I missing something in the way subresources should be implemented?
Solution 1
If you can use regexp checks instead of your isIdValid method it's possible to define your resources like this
#POST
#Path("objects/{id:\\d+}")
public Response doSmth(#PathParam("id") String id) {
...
}
In a case of invalid id format caller will have 'Not Found' response status without even reaching your doSmth method.
Obviously, you can use String constants for all equal path values.
final static String ID_RES = "objects/{id:\\d+}";
#POST
#Path(ID_RES)
public Response postSmth(#PathParam("id") String id) {
...
}
...
#GET
#Path(ID_RES)
public Object getSmth(#PathParam("id") String id) {
...
}
The can also read full description of Path#value parameter
Solution 2
Create and register at your REST server javax.ws.rs.container.ContainerRequestFilter implementation with filter method having needed URI checks.
The single filter parameter has ContainerRequestContext type from witch you can call getUriInfo for getting URI and method abortWith(Response response) which can be used for aborting caller request if your resource ids validation was failed.
See Chapter 10. Filters and Interceptors chapter of Jersey Manual.
I'm looking for a way to provide multiple pieces of information for exceptions back to end users. The obvious solution of extending Exception ends up with text distributed throughput the code, for example
throw new MyException("Bad data", "The data you entered is incorrect", "http://www.example.com/moreinfo/baddata");
and this quickly becomes unworkable.
I then looked at a catalogue approach but that's too centralized and requires jumping around from one file to another every time an exception is thrown. I'm now considering a hybrid approach with a static ErrorInfoMap class that contains mappings from a key to the more detailed information. Each class then has a static section that contains its own error mappings, so using the class which throws the above exception as an example I'd change it to:
throw new MyException("Bad data");
and at the bottom of the class there would be something like:
static {
ErrorInfoMap.put("Bad data", new ErrorInfo("The data you entered is incorrect", "http://www.example.com/moreinfo/baddata"));
// Information for other exceptions thrown by this class goes here
}
which allows an exception handler to fetch the additional information if required. Is this a good way of solving this issue, or is there a better way to handle this?
I'm not sure what exactly you mean by "the catalog approach" (could you provide a reference or more detailed description?) but from the information you provided, it's not clear to me how a static ErrorInfoMap avoids the problem of being "too centralized and [requiring] jumping around from one file to another every time an exception is thrown".
To me there are several options, depending on exactly what you need to accomplish:
Create a root class, ExceptionTemplate that extends Exception and does whatever repeatable behavior you'd like all your exceptions to do. Formatted toString() methods are a good example. Depending on your exact goals, you might like having your exceptions implement a builder pattern, like so:
throw new BadDataException("Supplied data is not valid")
.expected("a positive integer")
.referenceUrl("http://www.example.com/moreinfo/baddata");
Avoid stringly-typed solutions where an enum or subclass will do. If you don't need to define new exception types at runtime (and if you do, that should be a red flag that there's something deeper wrong with your design) and have an enum that contains all the necessary information to construct your exceptions:
public class EnumException extends Exception {
private EnumException() {} // prevent objects from being instantiated elsewhere
public enum Type {
BAD_DATA("Bad Data","Supplied data is not valid", "http://www.example.com/moreinfo/baddata"),
MISSING_DATA("Missing Data","Required data not found", "http://www.example.com/moreinfo/missingdata");
Type(String title, String genericMessage, String url) {
// Store input
}
public EnumException exception() {
// construct your exception
return new EnumException();
}
}
}
Which can be called with something like:
// note no `new` - the exception is returned by the enum
throw EnumException.Type.BAD_DATA.exception().expected("a positive integer");
This has the advantages of ensuring compile-time type safety, while still giving you the flexibility to define different types of Exceptions in one place.
Create lots of exceptions. I'm still not totally sure what objection you have to just creating a bunch of exceptions. You're looking for ways to "provide additional information" but claim that "the obvious solution of extending Exception ends up with text distributed throughput the code". This shouldn't be the case. Every subclass of Exception should hold all the necessary information except what can only be provided at construction time. Therefore there should be minimal "text distributed throughout the code" as any boiler-plate / reusable strings should be in the Exception class, and nowhere else.
public class DocumentedException extends Exception
{
private String title;
private String genericMessage;
private String detailedMessage;
private String url;
// Generally avoid this long constructor, and define subclasses that only need detailedMessage
public DocumentedException(String t, String g, String d, String u) {
super(g + " - " + d); // sets the getMessage() return value to something sane
title = t;
genericMessage = g;
detailedMessage = d;
url = u;
}
public String toString() {
return title.toUpperCase()+"\n"+
genericMessage+"\n"+
detailedMessage+"\n"+
"More info on this error: "+url+"\n";
}
public static class BadData extends DocumentedException {
public BadData(String details) {
super("Bad Data", "Supplied data is not valid", details, "http://www.example.com/moreinfo/baddata");
}
}
public static class MissingData extends DocumentedException {
public MissingData(String details) {
super("Missing Data", "Required data not found", details, "http://www.example.com/moreinfo/missingdata");
}
}
}
Which you can then call simply with:
throw new DocumentedException.BadData("Username cannot contain whitespace");
Of course, if you expected to need to warn against username errors regularly, you could create an additional class:
public static class BadUsername extends BadData {
public BadUsername() {
super("Usernames can only contain letters, numbers, and underscores");
}
}
The goal, again, is to explicitly define a hierarchy of exceptions that handle all cases you anticipate needing to deal with, such that you avoid repeatedly defining the same strings throughout your application. I personally like the group-exceptions-into-inner-classes pattern I used above, it lets you be very explicit with your errors without creating hundreds of silly stub java files you need to look through constantly. I would say that every major package should have an associated exception-holding class that defines all necessary exceptions for that package.
An alternative to your hybrid approach would be to put the error mapping in the exception itself. When MyException is initialised with Bad data add in the ErrorInfo that you've shown, but also provide a range of constructors for MyException that allows you to override or supplement the default definition of what Bad data means.
You could always have "MyException" as the superclass and have the specific types of errors as subtypes of that. In terms of error messages, you can use static constants on the subtypes to store the different types of errors.
E.g
Exception
-> MyException
-> BadDataException
-> InvalidUserException
etc.
Would be throw like so:
throw new BadDataException(BadDataException.DATA_TOO_LONG);