Spring Data Rest - customize endpoint name - spring

By default, Spring data REST use camelCase for endpoint names.
For example, if the repository is
#RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends PagingAndSortingRepository<User, Integer> {
List<User> findByUsername(#Param("username") String username);
}
Then the endpoint is http://localhost:8080/users/search/findByUsername?username=test
How can I customize the endpoint so it use snake_case, became like this: http://localhost:8080/users/search/find_by_username?username=test
Or even different method name
change find_by_username : http://localhost:8080/users/search/by_username?username=test
(stripping the find_by_username): http://localhost:8080/users/search?username=test
Thanks

The #RestResource annotation also gives us the ability to customize the URL path mapped to a repository method and the link id in the JSON returned by the HATEOAS resource discovery.
To do that, we use the optional parameters of the annotation:
path for the URL path
rel for the link id
By executing a cUrl to http://localhost:8080/users/search/, we can now see our new method listed with other resources:
{
"_links": {
"findByUsername": {
"href": "http://localhost:8080/users/search/findByUsername{?username}"
},
"self": {
"href": "http://localhost:8080/users/search/"
}
}
}
So to customize the rest url endpoint, we can simply add the #RestResource annotation:
#RestResource(path = "byUsername", rel = "customFindMethod")
List<User> findByUsername(#Param("username") String username);
If we do the resource discovery again, the resulting JSON will confirm our changes:
{
"_links": {
"customFindMethod": {
"href": "http://localhost:8080/users/search/byUsername{?username}",
"templated": true
},
"self": {
"href": "http://localhost:8080/users/search/"
}
}
}
For more details you can check her

Related

How to customize Spring Data REST to use a custom path for a repository resource?

I'm developing a microservice using SPRING DATA REST where I need to sub-resources to be accessible only thru main resource like the following structure :
http://localhost:8080/posts
http://localhost:8080/posts/1/comments
and block direct access to sub-resource directly like this http://localhost:8080/comments/*.
where comments must be accessible only thru related poste , I did the following in my repository :
#RepositoryRestResource(collectionResourceRel = "posts", path = "posts")
public interface PostRepository extends PagingAndSortingRepository<Post, Long> {
...
}
for comments :
#RepositoryRestResource(collectionResourceRel = "comments", path = "comments")
public interface CommentRepository extends PagingAndSortingRepository<Comment, Long> {
...
}
now by default SPRING DATA REST returns the following results when i goto to : http://localhost:8080
{
"id": 1,
"content": "some post text .........................",
"author":"abc",
"_links": {
"self": {
"href": "http://localhost:8080/posts/1"
},
"attributes": {
"href": "http://localhost:8080/posts/1/comments"
}
}
}
now if i want to post a comment i need to do the following :
http://{server:port}/comment METHOD:POST
{"author":"abc","content":"PQROHSFHFSHOFSHOSF", "post":"http://{server:port}/post/1"}
but what i need to achienve is to POST to an url like this http://{server:port}/posts/1/comment where the POST is the root resource NOT like the previous path http://{server:port}/comment
http://{server:port}/posts/1/comment METHOD:POST
{"author":"abc","content":"PQROHSFHFSHOFSHOSF", "post":"http://{server:port}/post/1"}
i now that this is possible if a create a custom comment #controller but i want to use the already building features of SPRING DATA REST and Hateoas support .

SPRING HATEOS LINKS (HTTPS vs HTTP)

I have a simple rest service which returns the response when a GET operation is performed along with the HATEOS links. When the service is deployed on the server and is accessed through a load balancer url (Https), the links section contains the url with "http" instead of "https". Any example solution/code for this particular scneario would help me.
For Example:
If a GET operation is performed by using the url(https://servicename.example.com) then I would expect the same url to be in the links section. But I receive something like below.
Response Body:
{
"fieldA": null,
"fieldB": null,
"links": [
{
"rel": "self",
"href": "http://servicename.example.com" // It has to be https
}
]
}
Below is the line of code that adds the links to the Rest Resource that will be exposed to the consumer.
resource.getLinks().add(linkTo(methodOn(ExampleController.class).methodInExampleController(arg a, arg b)).withSelfRel());
The resource that is being exposed to the consumer extends another class"ResourceSupport" where a field called links is declared which is of type List.
Example of Resource class:
imnport com.examplepackage.ResourceSupport
public SampleResource extends ResourceSupport{
private String fieldA,
private String fieldB,
//setters and getters
}
Example of the class where HATEOS Links are declared
import org.springframework.hateoas.Identifiable;
import org.springframework.hateoas.Link;
public ResourceSupport implements Identifiable<Link>{
#JsonInclude(Include.NON_EMPTY)
private final List<Link> links = new ArrayList();
#JsonProperty("links")
public List<Link> getLinks() {
return this.links;
}
}
SPRING HATEOS version: spring-hateos0.24.0.RELEASE

Spring Data Rest, SpringFox and JpaRepository custom finders

NB: using Spring Boot 1.4.2 + SpringFox 2.6.0
Hi, I'm having an issue with Swagger 2 forms on my API documentation over a #RepositoryRestResource. The code below works fine (REST access OK):
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends JpaRepository<Person, Long> {
Person findByLastName(#Param("name") String name);
}
And the HATEOAS links are right too: calling URL /api/people/search
ends up with this (notice parameter "name"):
{
"_links": {
"findByLastName": {
"href": "http://localhost:8080/api/people/search/findByLastName{?name}",
"templated": true
},
"self": {
"href": "http://localhost:8080/api/people/search"
}
}
}
The REST API is ok: URL /api/people/search/findByLastName?name=foobar returns data when executed with a browser
BUT in Swagger the GET parameter type is interpreted as "body" instead of "query" and the form submission (curl ... -d 'foobar'...) fails in 404, attempting to submit "name" as request body.
So I tried to set Swagger explicitly, like this:
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends JpaRepository<Person, Long> {
#ApiOperation("Find somebody by it's last name")
#ApiImplicitParams({
#ApiImplicitParam(name = "name", paramType = "query")
})
Person findByLastName(#Param("name") #ApiParam(name = "name") String name);
}
without any success, despite the fact that "name" is well retained in the form as the parameter name in this example :-(
body parameter type on GET query
Does anyone know what could be done to make that Swagger form to work? Thx for your help
This is it : #Param configures Spring Data REST, while #RequestParam fits Swagger
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends JpaRepository<Person, Long> {
// #Param Spring Data REST : Use #Param or compile with -parameters on JDK 8
// #RequestParam Swagger : paramType=query cf. $Api*Param
Person findByLastName(#Param("name") #RequestParam("name") String name);
}
Me happy!

spring hateoas generates different responses for collection or pojo

I have two classes
import org.springframework.hateoas.ResourceSupport;
public class A{}
public class B{}
public class AResource extends ResourceSupport {
private final A a;
}
public class BResource extends ResourceSupport {
private final B b;
}
#Controller
public class Controller {
#RequestMapping
#ResponseBody
public Set<AResource> giveMeColl() {
}
#RequestMapping
#ResponseBody
public BResource giveMeSingle() {
}
}
both responses add links object but for resource A is "links" and for resource B is "_link" and also structure changes
//RESPONSE FOR A
[
{
"content":{
//my fancy object
},
"links":[
{
"rel": "self",
"href": "http://localhost:8080/myid/22"
}
]
}
]
{
"content":{
//my fancy object
},
"_links":[
{
"self": "http://localhost:8080/myid/22/someelse/33"
}]
}
both resources are constructed with assemblers and both are adding the link from the ids
AResource aresource = new AResource(a);
resource.add(linkTo(methodOn(Controller.class).giveMeColl()).withSelfRel());
BResource bresource = new BResource(b);
resource.add(linkTo(methodOn(Controller.class).giveMeSingle()).withSelfRel());
Response headers for a is
"content-type": "application/json;charset=UTF-8"
and for b
"content-type": "application/hal+json;charset=UTF-8"
Could it be because returning an array is not really Restful? as Some post suggest
p.s. I have added and removed #EnableHypermediaSupport but doesn't seem to affect the problem.
"_links" follows the HAL specification. Spring HATEOAS includes a dedicated serializer for that, but it is only used for classes that extend ResourceSupport.
Returning a simple array is not exactly "unRESTful", but it doesn't meet the REST maturity level 3 (Hypermedia controls). In order to achieve that you can wrap the collection into a Resources instance, which extends ResourceSupport. You should get the same link serialization for both types then.

Handle subclass of arraylist as an array

We have an Jersey REST-API annotated with Swagger annotations.
The swagger UI works with the exception of one class. This class extends ArrayList<T>. And I expect that this class is handled by swagger as an array. But this is not the case. It is handled like any other complex object and its public members are shown in swagger-ui.
Here a code summary of my class:
#JsonAutoDetect(getterVisibility = Visibility.NONE, fieldVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
public class ArraySubClass extends ArrayList<ElementClass> implements IAnInterface {
// constructors...
public A getA() {
// ...
}
}
Swagger shows this class as model object:
"ArraySubClass": {
"id": "ArraySubClass",
"description": "",
"properties": {
"a": {
"$ref": "A"
},
"empty": {
"type": "boolean"
},
"size": {
"type": "integer",
"format": "int32"
}
}
}
What can I do, so that swagger does handle the class (extending from ArrayList<T>) as an array and that swagger just shows its elements and not other properties?
you can rather use the class ElementClass directly in swagger as this
#ApiOperation(value = "/yourEndPoint", notes = "comment for endpoint", response = ElementClass.class, responseContainer = "List")
So that you'll present the content of your class as a list in the return and not your ArraySubClass that may contains others datas / stuff you want to hide ! :)
For more info : see response container

Resources