Is it possible to use annotations (at field-level) to provide description for fields?
I know I can use description method for that
.andDo(document("index", responseFields(
fieldWithPath("contact").description("The user's contact details"),
but I would prefer to put that description together with field definition, in my response object.
class IndexResponse {
//The user's contact details
String contract;
}
I know that I could have generated constraint descriptions (http://docs.spring.io/spring-restdocs/docs/current/reference/html5/#_using_constraint_descriptions_in_generated_snippets) but it generated description only for validation annotations.
I am looking for something like https://github.com/swagger-api/swagger-core/wiki/Annotations#apimodelproperty from Swagger.
It doesn't. I'm the lead of the REST Docs project and it's my opinion that annotations aren't a good way to write documentation. If you disagree with that opinion and want to use annotations, you could write an add-on that's similar to what's done from constraint descriptions. You could pass it a class to introspect and automatically generate FieldDescriptor instances that you can then pass into the request and response field snippets.
We built an extension to Spring REST Docs that allows using Javadoc for field descriptions:
class IndexResponse {
/**
* The user's contact details
*/
String contract;
}
But currently this only works if Jackson and MockMvc tests are used.
Project: https://github.com/ScaCap/spring-auto-restdocs
An introduction article: https://dzone.com/articles/introducing-spring-auto-rest-docs
Related
{"vehicle_number": "KA222009","vehicle_type":"sedan"}
This json I am sending a POST request and it gets saved !! I have used Request body serverside in spring boot so its fine up to here but when I send like
{"vehicle_number": "KA222009","vehicle_type":"sedan","username":"abc"}
this also gets saved with the matching attribute of my RequestBody class. I don't want in this way and restrict the user to play with the request. How can I do this?
Do you have an entity to save that request into? Like
class Vehicle{
String vehicle_number;
String vehicle_type;
}
You'd need to put in the parameters then something like this
myfunction(#RequestBody Vehicle vehicle)
I believe an exception should be thrown by then.
edit 1:
The class Vehicle should be annotated with #Entity
And it's good practice to return a ReponseEntity<?> instead of actual data types
edit 2:
On another note, if you want your Vehicle entity to have a username but restrict the user from changing the username, then you just have to exclude it from the Vehicle constructor.
To add to Rei Brown's answer, you will likely not only want to create a data class, you will also want Bean Validation on it. For example:
#RequestMapping(/*....*/)
public void save(#Valid #RequestBody Vehicle vehicle){
// ... save logic here
}
Spring supports annotation based validation at the controller level.
(1) Is it necessary to do such validations also at the RestTemplate level for responses from REST calls?
If the answer is Yes:
(2) Will there be support for that at the RestTemplate to validate responses from rest calls sometime in the future?
If the answer is No:
(3) why?
It is 2020 now and I still do not see the requested feature in place.
The #Valid is nice to automatically validate e.g. a posted RequestBody.
But for the validation of the body of a ResponseEntity fetched via RestTemplate, I do not see any fancy equivalent.
So the only option I know, is to do it on your own taken from here. Input is the class of your RequestEntitys body. input is the body itself.
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Input>> violations = validator.validate(input);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
So to answer your question:
Yes I would validate the response!
future (2020) has not brought the feature you and I miss
For the reason why this is missing, I also have no answer.
For me, the questions are quite big. :). As my understanding, you would like to ask the validation in REST service that Spring can support.
1. Is it necessary to do such validations also at the RestTemplate level for responses from REST calls?
Actually, it depends on your apps or your business. You can do at Controller or you can do in Service Level or even you can do your custom validation. For me, no one forces you to do anything.
However, as my experience, we should do the validation for sure. So my answer here is YES.
2. Will there be support for that at the RestTemplate to validate responses from rest calls sometime in the future?
I assume that you would like the detail of the validation?! Right?
Spring supports many things to do the validation. For the simple way, you can use PathVariable or RequestParameter.For example:
#GetMapping("/test/{name}")
private String test(#PathVariable(value = "name", required = true) String name){
//...
}
Spring will validate all requests, and respond with 400 Bad Request when the required parameter is missing or has a wrong type...
Spring also supports the JSR 303 Bean Validation: http://beanvalidation.org/1.0/spec/ For example in here:
public class MessageBean {
#NotNull
private String title;
#NotNull
private String message;
// getters/setters/etc
}
Or you would like to do the Custom User Response like:
#ExceptionHandler
#ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleException(MethodArgumentNotValidException exception) {
//....
return ErrorResponse.builder().message(errorMsg).build();
}
Some more details in here: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-validation
So, it depends on the business which requires us to do the validation at any level.
3. If the answer is No: (3) why?
No need to answer this. :)
Hope that helps
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);
...
We have a backend built on FOSRestBundle (JMSSerializer) based on Symfony2/Doctrine2.
Our API e.g. delivers for some entity something like: 'valid_from': '2015-12-31' in a REST/JSON response.
Our AngularJS frontend consumes this REST API and e.g. presents some form to the user:
Valid from: 31.12.2015
Now I am wondering what's the best way to have a central/or maintainable place for a mapping like:
an English label for field key 'valid_from' is 'Valid from'
To my understanding all Translatable extensions for Doctrine (like Gedmo Kpn etc.) are to translate content (e.g. 'category' = 'Product' in English and = 'Produkt' in German) but not schema.
And of course I cannot change/adapt the field key to the language because it's the identifier for the frontend.
What I thought so far:
Use some mapping file between field_key, language_key and
translation on frontend.
Issue here is that the frontend needs to know a lot and ideally any change in the API can be done thoroughly by the backend developers.
Use some mapping file between field_key, language_key and
translation on frontend.
As we use annotations for our Entity model and JSMSerializer I'd need to open a totally new space for just translation information. Doesn't sound too convincing.
Create custom annotation with properties
Current idea is to use custom annotation (which would be cacheable and could be gathered and provided as one JSON e.g. to the frontend) with my entity properties.
That means any backend developer could immediately check for translation keys at least as soon as the API changes.
Something like:
#ORM\Column(name='product', type='string')
#FieldNameTranslation([
['lng'=> 'de-DE'],['text']=>'Product'],
['lng'=> 'en-En'],['text']=>'Produkt'])
A further idea could be just to provide some translation key like:
#FieldNameTranslation(key='FIELD_PRODUCT')
and use Symfony's translation component and have the content in translation yml files.
What is your opinion? Is there any 'best in class' approach for this?
I've an entity with an ID of
public string ID {get;set;}
activities/1
(which comes from RavenDB).
I'm registering the following routes in my ServiceStack AppHost
Routes
.Add<Activity>("/activities")
.Add<Activity("/activities/{id}");
I'm using a backbone app to POST and PUT to my REST Service.
What happens out-of-the-box:
id property is serialized into the json as "activities/1"
id property is encoded into route as "activities%2F1"
ServiceStack gives precedence to the URL based id property, so my string gets the encoded value which is no use to RavenDb directly.
The options I'm aware of:
Change backbone to post to "/activities" and let the JSON Serialiser kick in
Change RavenDb ID generation to use hyphens rather than slashes
Make my Id property parse for the encoded %2F on set and convert to a slash
Both have disadvantages in that I either lose RESTfulness in my API, which is undesirable, or I don't follow RavenDb conventions, which are usually sensible out-of-the-fox. Also, I've a personal preference for having slashes.
So I'm wondering if there are any other options in servicestack that I could use to sort this issue that involve less compromise? Either Serialiser customisation or wildcard routing are in my head....
I have the same problem with ASP.Net WebAPI, so I don't think this is so much a ServiceStack issue, but just a general concern with dealing with Raven style id's on a REST URL.
For example, let's say I query GET: /api/users and return a result like:
[{
Id:"users/1",
Name:"John"
},
{
Id:"users/2",
Name:"Mary"
}]
Now I want to get a specific user. If I follow pure REST approach, the Id would be gathered from this document, and then I would pass it in the id part of the url. The problem here is that this ends up looking like GET: /api/users/users/1 which is not just confusing, but the slash gets in the way of how WebAPI (and ServiceStack) route url parameters to action methods.
The compromise I made was to treat the id as an integer from the URL's perspective only. So the client calls GET: /api/users/1, and I define my method as public User Get(int id).
The cool part is that Raven's session.Load(id) has overloads that take either the full string form, or the integer form, so you don't have to translate most of the time.
If you DO find yourself needing to translate the id, you can use this extension method:
public static string GetStringIdFor<T>(this IDocumentSession session, int id)
{
var c = session.Advanced.DocumentStore.Conventions;
return c.FindFullDocumentKeyFromNonStringIdentifier(id, typeof (T), false);
}
Calling it is simple as session.GetStringIdFor<User>(id). I usually only have to translate manually if I'm doing something with the id other than immediately loading a document.
I understand that by translating the ids like this, that I'm breaking some REST purist conventions, but I think this is reasonable given the circumstances. I'd be interested in any alternative approaches anyone comes up with.
I had this problem when trying out Durandal JS with RavenDB.
My workaround was to change the URL very slightly to get it to work. So in your example:
GET /api/users/users/1
Became
GET /api/users/?id=users/1
From jQuery, this becomes:
var vm = {};
vm.users = [];
$.get("/api/users/?" + $.param( { id: "users/1" })
.done(function(data) {
vm.users = data;
});