Enterprise Java

Demo Project: How @BasePathAwareController Breaks Link Builders

This minimal example shows two controllers in a Spring Data REST app with base path /api:

  • One using @BasePathAwareController — link builder misses the base path.
  • One using @RepositoryRestController — link builder works correctly.

1. Setup Spring Boot and Dependencies

Add to pom.xml (or build.gradle):

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-hateoas</artifactId>
    </dependency>
</dependencies>

2. Configure Base Path

In application.properties:

spring.data.rest.base-path=/api

This sets the base path to /api.

3. Define a Sample Entity and Repository

@Entity
public class Book {
    @Id @GeneratedValue
    private Long id;
    private String title;

    // Constructors, getters, setters
}
@RepositoryRestResource(path = "books")
public interface BookRepository extends JpaRepository&;t;Book, Long> {}

Spring Data REST exposes /api/books.

4. Controller Using @BasePathAwareController

@BasePathAwareController
@RequestMapping("/books")
public class BasePathAwareBookController {

    @GetMapping("/{id}")
    public ResponseEntity<Book> getBook(@PathVariable Long id) {
        // For demo, just a stub Book
        Book book = new Book();
        book.setId(id);
        book.setTitle("Sample Book");
        return ResponseEntity.ok(book);
    }

    @GetMapping("/{id}/link")
    public ResponseEntity<String> getLink(@PathVariable Long id) {
        Link link = WebMvcLinkBuilder.linkTo(
            WebMvcLinkBuilder.methodOn(BasePathAwareBookController.class).getBook(id))
            .withSelfRel();
        return ResponseEntity.ok(link.getHref());
    }
}

5. Controller Using @RepositoryRestController

@RepositoryRestController
@RequestMapping("/books")
public class RepositoryRestBookController {

    @GetMapping("/{id}")
    public ResponseEntity<Book> getBook(@PathVariable Long id) {
        Book book = new Book();
        book.setId(id);
        book.setTitle("RepositoryRest Book");
        return ResponseEntity.ok(book);
    }

    @GetMapping("/{id}/link")
    public ResponseEntity<String> getLink(@PathVariable Long id) {
        Link link = WebMvcLinkBuilder.linkTo(
            WebMvcLinkBuilder.methodOn(RepositoryRestBookController.class).getBook(id))
            .withSelfRel();
        return ResponseEntity.ok(link.getHref());
    }
}

6. Testing the Links

Run the app and test:

GET http://localhost:8080/api/books/1/link
}
  • For BasePathAwareBookController, the output will be:
/books/1

Notice: Missing /api prefix! This URL is broken because the actual endpoint is /api/books/1.

  • For RepositoryRestBookController, the output will be:
/api/books/1

This URL is correct.

7. Conclusion

This demo proves:

  • @BasePathAwareController causes WebMvcLinkBuilder to omit the base path /api.
  • @RepositoryRestController preserves the base path correctly in generated links.

If your app uses hypermedia links with Spring Data REST, prefer @RepositoryRestController for custom controllers to avoid broken links.

Bonus: Manual Fix for Base Path

If you must use @BasePathAwareController, add the base path manually in the link:

String basePath = "/api";
Link link = WebMvcLinkBuilder.linkTo(
    WebMvcLinkBuilder.methodOn(BasePathAwareBookController.class).getBook(id))
    .withSelfRel();

String fixedLink = basePath + link.getHref();  // prepend base path manually

But keep in mind this can become tedious and error-prone as your API grows.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button