1

Suppose I have Spring Data repository for a User entity. Then, Spring Data REST produces the following HAL JSON at its base path:

{
  "_links": {
    "users": {
      "href": "http://localhost:8080/users"
    }
  }
}

I also want my clients to know that they can call http://localhost:8080/users/{id} to get a specific user (e.g., http://localhost:8080/users/25)

How can I configure Spring Data REST to produce this link for all my entities? For example, I would like Spring Data REST to return something like this:

{
  "_links": {
    "users": {
      "href": "http://localhost:8080/users/{id}",
      "templated": true
    }
  }
}

Update

A good example of what I'm trying to achieve is at https://api.github.com/. The API clearly indicates that https://api.github/users/{user} is part of the API. For example, https://api.github.com/users/odrotbohm is a valid call.

How can I get Spring Data REST to indicate that htts://localhost:8080/users/{id} is part of my API?

Update 2

Does the CrudRepository provide a templated link http://localhost:8080/users/{id}? I don't see that it does. I'm using Javascript Traverson HAL and without this link I cannot traverse to a specific user.

Update 3

Here is a complete sample of the problem (that I also posted on github):

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'
}

group = 'com.example'
version = '1.0'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-rest'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

In com.example package:

TaversonIssueApplication.java

@SpringBootApplication
public class TaversonIssueApplication {

    public static void main(String[] args) {
        SpringApplication.run(TaversonIssueApplication.class, args);
    }

}

User.java

@Entity
@Table(name="`User`")
@Data
public class User {
 
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
}

UserRepository.java

public interface UserRepository extends CrudRepository<User, Long> {
}

In /src/main/resources:

INSERT INTO "user" (name) VALUES ('bob');
INSERT INTO "user" (name) VALUES ('sally');

Once application is started, a request to http://localhost:8080/ results in:

{
  "_links" : {
    "users" : {
      "href" : "http://localhost:8080/users"
    },
    "profile" : {
      "href" : "http://localhost:8080/profile"
    }
  }
}

From this response, a client has know way of knowing that http://localhost:8080/users/1 is a valid link. A Traverson HAL client cannot follow the link from http://localhost:8080/ to http://localhost:8080/users/1. This is because no templated link is provided such as ``http://localhost:8080/users/{id}`.

Is there a way for Spring Data REST to provide such a templated link. Could Spring Data REST produce the following in response to http://localhost:8080/:

{
  "_links" : {
    "users" : {
      "href" : "http://localhost:8080/users/{id}"
    },
    "profile" : {
      "href" : "http://localhost:8080/profile"
    }
  }
}
James
  • 2,876
  • 18
  • 72
  • 116
  • You control your service and what it returns. What prevents you from returning Json that will contain your line "href": "http://localhost:8080/users" – Michael Gantman Aug 07 '23 at 16:37
  • @MichaelGantman - It does return the line `"href": "localhost:8080/users"`. But I want it to also return `"href": "localhost:8080/users/{id}"`. I've updated my post with a complete example. – James Aug 07 '23 at 16:48
  • I meant to ask what prevents you from returning the value "href": "localhost:8080/users/{id}" – Michael Gantman Aug 07 '23 at 17:14
  • @MichaelGantman - How can I do that? That would answer my question. I want to return it for all my repositories (i.e., `users/{id}`, `permissions/{id}`, etc.). – James Aug 07 '23 at 17:56
  • I suppose there is something I don't understand or missing some info. You write the code that returns your Json. You can return {"Greetings":"hello World"} right? so what is stopping you to return "/users/{id}" instead of "/users" withing your json? – Michael Gantman Aug 07 '23 at 20:14
  • @MichaelGantman - I do **not** write the code that returns the JSON. Spring Data Rest is doing that. I would like to know how to configure Spring Data Rest to return `users/{id}`. – James Aug 07 '23 at 22:26
  • OK, that was a missing piece of info for me. Sorry, but I don't know the answer for that – Michael Gantman Aug 08 '23 at 09:43
  • @MichaelGantman - No problem. Thank you for your attempt to help. – James Aug 08 '23 at 14:22

1 Answers1

1

Just extend the PagingAndSortingRepository interface. It also provides additional methods for paging & sorting data.

@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends PagingAndSortingRepository<User, Long>, CrudRepository<User, Long> {
}

Please mind the @RepositoryRestResource annotation. It allows changing the export details like the name of the collection in the JSON response or as well as the base path for the repository. Please take a look at this official Spring guide

Ebrahim Pasbani
  • 9,168
  • 2
  • 23
  • 30
Angshuman
  • 60
  • 3
  • Although this will add `"templated ": true` and templated sorting and paging query parameters to the URL, this will not add a templated `id` path to the URL. In other words, it will not add a link to indicate the URL `http://localhost:8080/user{/id}` is a part of the RESTful API. – James Aug 03 '23 at 19:03
  • @James by extending `CrudRepository` Spring implements all crud methods, so you have them exposed in REST – Ebrahim Pasbani Aug 06 '23 at 15:52
  • @EbrahimPasbani - Does the `CrudRepository` provide a templated link `http://localhost:8080/users/{id}`? I don't see that it does. I'm using [Javascript Traverson HAL](https://github.com/traverson/traverson-hal) and without this link I cannot traverse to a specific user. – James Aug 07 '23 at 15:14
  • @James `CrudRepository` provides crud methods only. And because you annotated the interface `UserRepository` with `RepositoryRestResource` the REST endpoints will be provided too. For example you want `/users/{id}`. The corresponding repository method is `findById` which is in `CrudRepository`. The result is you made spring implement repository method and after that expose through REST endpoints. – Ebrahim Pasbani Aug 07 '23 at 16:30
  • @EbrahimPasbani - Annotating with `RepositoryRestResource` actually doesn't provide a templated link , `/users/{id}`. It only provides `/users`. There's is know way for a client such as a [Javascript Traverson HAL](https://github.com/traverson/traverson-hal) client to know that `/users/1` is a valid link. I've updated my OP with a full example. – James Aug 07 '23 at 16:53