Writing all fields with the snippets description is not reliable solution
is there any way to implement Model/Entity as a table with the fields and description, constraints, Type seprately.
fieldWithPath("id").description("Id of Student."),
fieldWithPath("name").description("Name of the Student."),
fieldWithPath("contact").description("Contact of the Student."),
fieldWithPath("marks").description("Marks of the Student."));
Documenting an entity directly is exactly what Spring REST Docs is designed to avoid. If that's the approach that you want to take then Spring REST Docs isn't the right tool for the job.
Spring REST Docs is built around the belief that, when documenting a REST API, it's the HTTP requests and responses that should be used to generate that documentation. This ensures that the documentation accurately describes the requests that the service expects to receive and the responses that it will send.
If you try to use an entity to document your API, you are ignoring the transformations that could be applied to that entity when serialising it to JSON. This can result in documentation that's inaccurate as serialization may omit some of an entity's properties, change the name of some of those properties, or even change the structure entirely.
Related
I'm new to Spring Boot and I just started using graphql-spqr for Spring Boot since it allows for easy bootstrapping of Java projects.
However, as per my understanding, GraphQL basically allows the fetching of selected fields from the database. As per the examples, I've seen, this type of selection in the graphql-spqr library happens on the client side. Is there a way to do selection both client-side and server-side so as to speed up the queries?
I've looked into EntityGraph examples for GraphQL but they are mostly implemented for complex queries that involve JOINs. However, nothing exists for simple queries like findAll(), findById() etc.
I would like to use findAll() with the server fetching only the fields as requested by the client. How can I do that?
What was said in the comments is correct: GraphQL (and hence SPQR, as it's merely a tool to hook the schema up) does not know anything about SQL, databases, JOINs or anything else. It's a communication protocol, the rest is up to you.
As for your situation, you'd have to inject the subselection into the resolver and pass it down to SQL. In the simplest case, it can look like this (in pseudo code):
public List<Book> books(#GraphQLEnvironment Set<String> fields) {
//pass the requested field names further
return database.query("SELECT " + fields + " FROM book");
}
You can inject ResolutionEnvironment using the same annotation, in case you need the full context.
To give you a background, we have an application with lots of REST services. Now for these services there are security permission entries. Now we could have an AccessVoter that intercepts all the request to check whether the user has permission to a resource but this is inefficient as we have to load thousands of rows from database and check the incoming request with the pattern saved in database. The pattern that I mentioned is exactly the same as the pattern that the developer put in their REST method, for example:
#PostMapping(value = "/accounts/{id}/advisers/{adviserId}")
Or
#PostMapping(value = "/accounts/{id}/advisers/address/{adrId}")
You can see how complex it can be and going through the records to find a match is expensive while Spring has already done the mapping and it can find the associated method very nicely.
We could create an aspect to check the permissions before the method invocation but at that time is too late as there are validation layers that happens before
I was thinking if we could have an access voter and then ask Spring to give us the method that it's going to invoke so that we can read the annotation, in above example #PostMapping and then find the pattern (say e.g. /accounts/{id}/advisers/{adviserId}) so we can only query that pattern from database, then this will be very efficient and less complex in our code.
The question is whether it's possible to get this information from Spring Boot or not?
Is there any other way than using Spring's AccessVoter to do the job? For example when we configure ResourceServerConfigurationAdaptor we have this code:
http.authorizeRequests()
.antMatchers(oAuth2AuthenticationSettings.getProtectedUrlPattern().split(","))
.authenticated().accessDecisionManager(accessDecisionManager);
As you can see accessDecisionManager is the one that returns AccessVoter but we could also set .authenticated().expressionHandler(...) which I don't know what it is used for. Can it be used for our purposes?
We don't want to use #PreAuthorize as it means we have to go and annotate all of our REST services.
I need to implement complex search feature using Spring Boot REST and Spring Data JPA using Criteria API. I need to provide RPIs like below
/college?select=*&where=name:DemoCollege and location:LA and staff{firstName:foo, lastName:boo, workExp>10} and type in [1,2,3]
Collage object has name, location, type fields and staff list.
It has onetomany relationship with Staff so College can have one or many Staff members.
based on the uri I need to build query using criteria api.
I am finding it very complex to implement the toPredicate() method of org.springframework.data.jpa.domain.Specification. Is there any such example handing such complex search filters?
Thanks in advance.
I think the best choice, in your case, is the specification-arg-resolver lib that provide convenient way to build specification declaratively. For example, this code:
#RequestMapping("/customers")
public Object findByName(
#And({
#Spec(path="registrationDate", params="registeredBefore", spec=DateBefore.class),
#Spec(path="lastName", spec=Like.class)}) Specification<Customer> customerSpec) {
return customerRepo.findAll(customerSpec);
}
is corresponding to this request:
GET http://myhost/customers?registeredBefore=2015-01-18&lastName=Simpson
It supports the following specifications: Like, LikeIgnoreCase, Equal, EqualIgnoreCase, In, Null, NotNull, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, DateBetween, Join, Join fetch, and it allows you to combine them, composing complex expressions.
Another option is Querydsl and Web support Spring Data extensions. It also allows you to build a 'REST query language' but has fewer possibilities. You can read in my answer how to use it: https://stackoverflow.com/a/48596145
Hi I want to parse a json that i retrieve by hitting an legacy system, and build a response json. We are using Spring Boot having a jackson dependency. The problem i have is almost 75% of fields from legacy can be mapped directly or on basis of simple rules (0: false, 1:true). But, there are some complex rules as well like based on certain conditions and data present in some fields, we can map them to a nested object etc. To cater to this requirement which approach should we consider -
POJO approach to fetch the data from legacy target. Use bean util. copyproperties to populate the response bean (75% of properties), and then apply the business transformations on this POJO to tranform based on business logic. (Would we need two pojos here a. to copy from beanutil.copyproperties and then b. create final response dto ??)
Do not use pojo directly parse the JSON apply the transformations and then create a new POJO or response DTO. (But, this may not be generic solution and would need to be done on case by case basis).
Main considerations are approach should be fast, and generic to be applied like a framework. Thanks aakash
The considerations should be like below:
- Are the POJOs reusable?
- Is the JSON multilevel and very large?
If the answer is yes for both, then better to choose POJOs for cleaner implementation. Otherwise JsonObject parsing.
Hope this will help.
I am using Jersey to implement rest api and Jackson to provide JSON support. I am trying to remove certain properties before serialization by overriding BeanSerializerModifier.changeProperties method.
But removing properties will be based on query parameter. Is there any way to access the query parameter in my implementation?
Use of BeanSerializerModifier itself would get complicated as the method is only called once when construction necessarily JsonSerializer for the first time. As to passing query parameters, you could pass them using contextual attributes and ObjectWriter (constructed from ObjectMapper), but that means taking over quite a bit of serialization automation from Jersey.
There is one mechanism that could be helpful in modifying serialization aspects without taking over the whole process: registering ObjectWriterModifier, using ObjectWriterInjector. These are part of Jackson JAX-RS provider, added in Jackson 2.3. Without knowing more details I don't know how easy this would be; part of the issue is that query parameters are more of an input side things, so there is no direct access to them from output processing side.