Alright, I've been put in charge of both the server and client (used internally) part of this RESTful architecture. (using restlet).
We've got a resource that exposes the Post operation. Here's a simplified version:
public class UserResource {
#Post
public Representation create(UserRegistration registration) {
SomeService.getInstance().createUser(registration);
return new XstreamRepresentation(new RegistrationResponse(registration.getUniqueCode()););
}
For a few months, we've been the only ones using these services, so domain objects were shared across client and server sides... and it's been working just fine.
Now that we have to document these resources and let other clients use them some "issues" have been arising that made me think this API might be a little too complicated.
This Post service, for example.
The internal method accepts complex type UserRegistration
public class UserRegistration implements Serializable {
private Profile profile;
private Boolean someBooleanProperty;
public UserRegistration(Profile profile) {
this(profile, true);
}
public Profile getProfile() {
return profile;
}
public boolean isSomeBooleanProperty() {
return someBooleanProperty;
}
}
which, in turn, uses another complex object (Profile)
public class Profile {
private String nickname;
private String email;
private String password;
private String firstname;
private String lastname;
private Date birthDate;
private String phone;
private Address address;
private GenderType gender;
private String subscriptionSite;
private Date privacyAcceptanceDate;
private Date subscriptionDate;
private String activationCode;
private String socialSecurityNumber;
...
which is using a lot of complex types and so on.
This use of complex types is what really bugs me.
I either don't know how to document this (apart from making a long long list of these complex objects inner properties) or I'm just lost.
My questions are:
Do I have to simplify?
Is this architecture very bad-designed?
Would a few builder methods do the trick?
By sharing domain entity types between the client and the server, you (not saying you specifically) have completely defeated the point of REST. RESTful systems are supposed to share only media types and link relations. Sharing types like you are doing is much easier with SOAP because WSDL allows toolkits to take care of the details of keeping the client and server types in sync.
REST is all about reducing the coupling between client and server to allow them to evolve independently. Obviously, if you have a large set of shared types, that is going to be difficult, which why you currently have this bad feeling.
The solution I have taken to this problem is to define two media types. One is sort of a generic entity data container. Let's call it BusinessDocument, and the other is called BusinessLayout. The client uses the BusinessDocument to retrieve all the data from the server and the BusinessLayout provides "data binding" information so the client knows where in my UI to display the different pieces of business data.
By doing this I am able to build a client that really doesn't understand the specifics of the data it is dealing with, it just knows how to display it on the UI for the user to interact with. By doing this, I am able to use a single media type, to describe hundreds of different business entities.
There's no need to give the java client to external consumers. Your API should be able to answer to any Http client. The fact that there is a java client that shares the object can depend on different factors but should not influence how you expose your REST API to third party consumer.
So I'd suggest to start writing a pure HTTP client, using apache commons HTTP, to see how your REST API behaves.
The fact that the server objects are complex also should not be of any interest of the API. If the old system was designed modeling object around data, which I consider a bad idea, that's something you have to deal with.
From the REST API you always receive just text, XML or JSON, and you have eventually to parse it into your Java Object, if you have for example and ORM + RDBMS backed system. If you could store Json, like on a a document DB, you do not have this problem but, again, this is of no concern of the REST API per se, but you need a layer that transform JSON to Java Object.
Restlet helps you with this, of course such complicated object is not an easy one to be automagically converted.
Related
I have dived into the documentation, but only find circular references to the mechanical aspects of the use of webCleint, without any concrete examples… And nothing that merges it with the use of #JsonView.
I have a microservice that accepts a DTO from the client, performs basic validation, then wants to pass it on to another microservice. But, in passing it on, I want to strip out fields, per a JsonView.
Basic User DTO
#JsonView({Views.Incoming.class,Views.Internal.class})
private String email;
#JsonView({Views.Incoming.class,Views.Internal.class})
private String password;
#JsonView(Views.Incoming.class)
private String passwordCheck //validated as matching in first service, not needed when handed off.
How do I a) actually build a webClient, make a request with it, and return a usable result, and b) give it my DTO filtered by #JsonView(Views.Internal.class)?
(The documentation about webClient itself is confusing, in that it suggests that a separate one is needed for each request (differentiating it from restTemplate), but the examples I have found instantiate one as static in the sercive class…)
For instance, if I'm hosting a site where users can upload videos, they should be able to modify the title, description, thumbnail, etc... But what's stopping them from modifying the current views? The upload time? Fields that they should NOT be able to change. Couldn't they use a REST tool like Postman and simply send a custom request in JSON format modifying all of these fields? They could potentially set their views to 999999999 if they wished.
My question: Do I need to add a large number of checks to prevent this? If not, what measures must be taken in order to prevent this from happening?
EDIT
Here's an example with Spring which is what I'm using to build my back end:
#RequestMapping(value="/modify/{id}", method=RequestMethod.POST)
public ResponseEntity<String> modifyVideo(UserVideo modifiedVideo) {
UserVideo originalVideo = videoService.findOne(modifiedVideo.getId());
//Set the prohibited fields back to their original values (checks)
modifiedVideo.setTotalViews(originalVideo.getTotalViews);
...
//Map modifiedVideo to originalVideo once all prohibited fields are reset
}
Besides ensuring the user is authenticated (asserting that the user is who they claim to be) and authorized (asserting that the user is allowed to perform the action they intend to), you must assert that only the updatable fields are exposed your API. Do not expose all the fields for update if not all the fields can be updated.
DTO is a good way to achieve it, as already mentioned in this answer. DTO stands for Data Transfer Object. And this pattern was created with a very well defined purpose: transfer data to remote interfaces, just like web services.
With a DTO, you can expose only a set of attributes of the persistence entities and this approach will give you full control over the attributes you are receiving when creating or updating a resource.
To avoid the boilerplate code of mapping DTOs to/from persistence entities, you can use mapping frameworks. For instance, have a look at MapStruct, which is annotation based and works as a Maven Annotation Processor.
To give your DTOs better names, have a look at this answer.
Resetting all the prohibited fields is going to be very tedious and time consuming, it would be better if your design already provided a way of ensuring fields cannot be tampered with without all that extra code.
In my experience it would be better not to expose the fields you do not want to be tampered with.
A common design would be to have two distinct layers, one with a set of classes used to represent each of the logical services you want on each REST service. The other layer, your core, would expose the full suit of functions you require to achieve all the functions of your site, or perhaps just the video uploading portion. The REST layer classes would only have the fields you want in your incoming request from users (e.g. Name, Description, etc.), you would then map these fields to fields within your core business layer classes which is at your discretion and within your control.
Hope this answers your question.
Code sample:
public class ModifyVideo {
private String name;
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
#RequestMapping(value="/modify/{id}", method=RequestMethod.POST)
public ResponseEntity<String> modifyVideo(ModifyVideo modifyVideo) {
try {
UserVideo userVideo = new UserVideo();
userVideo.setName(modifyVideo.getName());
userVideo.setDescription(modifyVideo.getDescription());
videoService.updateUserVideoMetadata(userVideo);
} catch (SomeCaughtException e) {
//log the error
return new ResponseEntity<Error>(HttpStatus.UNPROCESSABLE_ENTITY);
}
return new ResponseEntity<Success>(HttpStatus.OK);
}
This is a code style and architectural question. And it is not specific only for iOS or Android. What is the best and the most correct way for declaring\storing REST api's endpoints(urls) in the client app? Let's say I have a client app for some social network or whatever rest service. This service has a lot of different api endpoints: user/login, user/profile, common/list and so on and so forth. There can be a large number of this endpoints. So the question how should I correctly manage this in my client's app? Right now I just declare string constants like this for iOS: static NSString * const kLoginUser = #"user/login", Swift: let loginUser = "user/login" or in Android: "private final String LOGIN_USER = "user/login".
But if the web-service is rather complex there can be 40-50 such string constants or more. And I wondered: maybe I do it in a wrong way, and there are more elegant ways for managing endpoints in REST clients? Any explanations or interesting approaches will be very helpful.
I don't think there's a better way as to hold the endpoint URLs (or unique parts of them) in some constants. If you read them from some configuration files, this is still a constant, that should not change in the runtime.
If you are overwhelmed by a large number of enpoints - group them. Respect the "S" of SOLID - group the related enpoints in one Class. E.g. put the methods accessing user/login, user/profile, user/something_else in a UserServices class, common/a, common/b, common/the_rest in CommonServices. The String constants with the enpoint URLs will be defined in this Services classes.
The way I generally see it done is to create an enum for your various service calls:
protected enum SpecificRestServiceMethods implements RestServiceMethods{
EXAMPLE_REST_CALL_ONE("/example/service/examplerestcallone"),
EXAMPLE_REST_CALL_TWO("/example/service/examplerestcalltwo"),
//etc etc
private String path;
private SpecificRestServiceMethods(String path){
this.path = path;
}
public String getName(){
return this.name();
}
public String getPath(){
return path;
}
}
Then just plop that chunk in whatever class is handling your general REST stuff.
I am developing an Android app using GAE on Eclipse.
On one of the EndPoint classes I have a method which returns a "Bla"-type object:
public Bla foo()
{
return new Bla();
}
This "Bla" object holds a "Bla2"-type object:
public class Bla {
private Bla2 bla = new Bla2();
public Bla2 getBla() {
return bla;
}
public void setBla(Bla2 bla) {
this.bla = bla;
}
}
Now, my problem is I cant access the "Bla2" class from the client side. (Even the method "getBla()" doesn't exist)
I managed to trick it by creating a second method on the EndPoint class which return a "Bla2" object:
public Bla2 foo2()
{
return new Bla2();
}
Now I can use the "Bla2" class on the client side, but the "Bla.getBla()" method still doesn't exit. Is there a right way to do it?
This isn't the 'right' way, but keep in mind that just because you are using endpoints, you don't have to stick to the endpoints way of doing things for all of your entities.
Like you, I'm using GAE/J and cloud endpoints and have an ANdroid client. It's great running Java on both the client and the server because I can share code between all my projects.
Some of my entities are communicated and shared the normal 'endpoints way', as you are doing. But for other entities I still use JSON, but just stick them in a string, send them through a generic endpoint, and deserialize them on the other side, which is easy because the entity class is in the shared code.
This allows me to send 50 different entity types through a single endpoint, and it makes it easy for me to customize the JSON serializing/deserializing for those entities.
Of course, this solution gets you in trouble if decide to add an iOS or Web (unless you use GWT) client, but maybe that isn't important to you.
(edit - added some impl. detail)
Serializing your java objects (or entities) to/from JSON is very easy, but the details depend on the JSON library you use. Endpoints can use either Jackson or GSON on the client. But for my own JSON'ing I used json.org which is built-into Android and was easy to download and add to my GAE project.
Here's a tutorial that someone just published:
http://www.survivingwithandroid.com/2013/10/android-json-tutorial-create-and-parse.html
Then I added an endpoint like this:
#ApiMethod(name = "sendData")
public void sendData( #Named("clientId") String clientId, String jsonObject )
(or something with a class that includes a List of String's so you can send multiple entities in one request.)
And put an element into your JSON which tells the server which entity the JSON should be de serialized into.
Try using #ApiResourceProperty on the field.
I was wondering how people with more experience and more complex projects get along with this "uglyness" in the REST Communication. Imagine the following Problem:
We'll need a fair amount of functionalities for one specific resource within our REST Infrastructure, in my case that's about 50+ functions that result in different querys and different responses. I tried to think of a meaningful resource-tree and assigned these to methods that will do "stuff". Afterwards, the Server Resource Class looks like this:
#Path("/thisResource")
public class SomeResource {
#GET/POST/PUT/DELETE
#Path("meaningfulPath")
public Response resourceFunction1 ( ...lots of Params) {
... logic ....
}
//
// lots of functions ...
//
#GET/POST/PUT/DELETE
#Path("meaningfulPath")
public Response resourceFunctionN ( ...lots of Params) {
... logic ....
}
}
To construct the urls my client will call, I made a little function to prevent Typos and to take better use of Constants
so my Client looks like this:
public class Client() {
public returnType function1 () {
client.resource = ResourceClass.build(Constants.Resouce, "meaningfulPath");
...
return response.getEntity(returnType);
}
}
Now the questions that bothers me is how could I link the client function and the server function better?
The only connection between these two blocks of code is the URL that will be called by the client and mapped by the server, and if even this URL is generated somewhere else, this leads to a lot of confusion.
When one of my colleagues needs to get into this code, he has a hard time figuring out which of the 50+ client functions leads to wich server function. Also it is hard to determine if there are obsolete functions in the code, etc. I guess most of you know about the problems of unclean code better than I do.
How do you deal with this? How would you keep this code clean, maintainable and georgeous?
Normally, this would be addressed by EJB or similar technologies.
Or at least by "real" web services, which would provide at least WSDL and schemas (with kind of mapping to Java interfaces, or "ports").
But REST communication is very loosely typed and loosely structured.
The only thing I can think of now, is: define a project (let's call it "Definitions") which would be referenced (hence known) by client and server. In this project you could define a class with a lot of public static final String, such as:
public static final String SOME_METHOD_NAME = "/someMethodName";
public static final String SOME_OTHER_METHOD_NAME = "/someOtherMethodName";
Note: a static final String can very well be referenced by an annotation (in that case it is considered to be constant by the compiler). So use the "constants" to annotate your #Path, such as:
#Path(Definitions.SOME_METHOD_NAME)
Same for the client:
ResourceClass.build(Constants.Resouce, Definitions.SOME_METHOD_NAME);
You are missing the idea behind REST. What you are doing is not REST but RPC over HTTP. Generally you are not supposed to construct URLs using out of band knowledge. Instead you should be following links received in the responses received from the server. Read about HATEOAS:
http://en.wikipedia.org/wiki/HATEOAS