0

I am developing a simple dictionary RESTful API with Spring-mvc. There are two related entities:

public class Word {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int id;

  private String word;

  @ManyToOne(fetch=FetchType.EAGER)
  @JoinColumn(name="LANGUAGE_ID", insertable=false, updatable=false)
  private Language language;

}

Based on the code above the related entity is Language.

Issue: I would like to implement the CREATE operation on the Word entity with POST request. The implementation is not difficult, but I did find at least two solution candidates in relation to the POST request URL and JSON request body:

Solution Candicate I: directly insert with JSON body request. The JSON body contain the nested JSON object - Language, something like

{id:1, word:"hello", Language: {id:1, language:"English"}}

reference: Spring: Save object with foreign keys with a POST request

Solution Candidate II: get the referenced Language id through the POST request URL, say something like

POST http://localhost:8080/rest/language/1/words

As such, there is no Language reference at all in the JSON POST request body.

reference: https://www.youtube.com/watch?v=_Jnu_jHfQbM

I have 2 questions:

Question 1: among these two solution candidates, which is the better one, or say professional standard solution? or is there any other solution?

Question 2: as to both the given solution candidate, in any case we need to retrieve the referenced Language POJO at least in the corresponding controller class. But from the perspective of OO-design principle, this way seems to be tightly coupled with the controller, so I am thinking that should we decouple this retrieval behavior somewhere else than in controller? for instance in the service layer. But is this the professional way? and we need to have a corresponding DTO?

Rui
  • 3,454
  • 6
  • 37
  • 70

2 Answers2

0

In my opinion the data which should be saved has to be nested in the body. Spring could map the json data directly into an object and you don't have to set it from parameter to another model class.

And i would create separate model classes for your entities. So the controller fills the data to the model classes and give them to a service. Then the service maps the model classes to entities. After that they could be stored via repositories.

Example:

@Controller
public class RestController {

  @Autowired
  RestService restService;

  @PostMapping(value="/")
  public void saveVariable( @RequestBody TestModel testModel ) {
    testService.saveTest( testModel );
  }
}

@Service
public class RestService {

  @Autowired 
  TestRespository testRepository;

  public void saveTest( TestModel testModel ) {
    TestEntity testEntity = new TestEntity();
    //some mapping from testModel to testEntity
    testRepository.save( testEntity );
  }
}
Benjamin Schüller
  • 2,104
  • 1
  • 17
  • 29
  • Thanks first for your advice :) What do mean "create separate model classes for your entities"? I did have 2 separate entities, say Language and Word. U probably I should have DTO? Seems the TestModel you have given is kinda DTO? – Rui Sep 14 '17 at 09:57
  • Yes, i don't like using entities in the controller. So i create a separate class which holds the values of the corresponding entity you need. – Benjamin Schüller Sep 14 '17 at 10:00
0

Assuming that words belong to a language, I would design it as following:

POST /api/languages/en/words HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{
  "word": "hello"
}

Where a representation of a word (a JSON document, for example) is sent in the request payload to a URL that represents a hierarchy (a language has words).

You also could use two-letter codes to identify the languages, since it's the way clearer than numeric values. In the above example, en means English.


I advise you to avoid exposing persistence entities in your REST API and use DTOs instead. Your REST resources representations don't need to have the same attributes as the persistence objects.


Keep your REST controllers as lean as possible and keep your service layer focused on business rules.

cassiomolin
  • 124,154
  • 35
  • 280
  • 359
  • Thanks a lot for your advice :) Great! – Rui Sep 14 '17 at 21:09
  • Your answet is OK, too. But answer from Benjamin is more acceptable from my point of view even though I would choose to your solution in most occasions. Moreover, Benjamin's answet came earlier. Sorry for this :) – Rui Sep 18 '17 at 09:20