springspring-bootkotlin

Spring Boot - How/Where to convert foreign key of a DTO to an Entity


I am making a REST service with Spring Boot, and I am having trouble at the point where I convert JSON requests/DTOs to the corresponding entities, specifically when an entity contains a reference to another entity. Say we have these objects for example:

data class BookEntity(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Int?,

    val name: String,

    @ManyToOne
    @JoinColumn(name = "author_id")
    val author: AuthorEntity,
)
data class AuthorEntity(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Int?,

    val name: String,
)
data class BookRequestDto(
    val name: String,
    val authorId: Int,
)

The application has controller-service-repository layers, and as far as I know I am supposed to perform the DTO -> entity conversion in the controller layer, and then pass the resulting entity to the service layer. However, in order to convert the book request DTO to an entity, I first have to fetch the appropriate Author entity from the repository based on the given authorId. My question is: where exactly should I do that?

Given that the service layer should only accept entities, it looks like I should do the author fetching in the controller layer. But that would mean that the Book controller would need to have access to the Author service layer, and that's what I'm not sure is good practice.

Here is what I mean (using obvious extension functions to do the DTO/entity conversions)

@RestController
@RequestMapping(path = ["/books"])
class BookController(
    private val bookService: BookService,
    private val authorService: AuthorService,
) {
    @PostMapping
    fun createBook(@RequestBody bookDto: BookRequestDto): ResponseEntity<BookResponseDto> {
        val author = authorService.get(bookDto.authorId)
        val bookEntity = bookDto.toBookEntity(author = author)
        val createdBook = bookService.create(bookEntity)
        return ResponseEntity(createdBook.toBookResponseDto(), HttpStatus.CREATED)
    }
}

Is this the usual way of doing this, or is mixing multiple services in a controller a bad idea? I clearly have to access the author repository somewhere, I just don't know where the best place would be. Is there a better way?


Solution

  • This might get closed as an opinion based question :), but ...