Как правильно создать и проверить Entity Model и ее DTO в RESTful API? - PullRequest
1 голос
/ 25 апреля 2020

Я разрабатываю свой первый RESTful API с нуля и с помощью Spring Boot.

Я уже создал конечные точки, модели и репозитории JPA для "автономных" объектов. Но теперь, когда я начал связывать их вместе и после некоторого исследования, я пришел к выводу, что мне, возможно, придется создавать DTO. Я не думаю, что каждый раз, когда я создаю новый Order с запросом POST, я должен заставить клиента отправлять целые объекты Customer и Employee внутри запроса как вложенные объекты Order (если я тоже неправильно в этом, пожалуйста, дайте мне знать). Я думаю о создании DTO, просто заменив отношения классов просто идентификаторами.

Вот как определяется моя сущность:

@Data
@Entity
@Table(name = "Orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @NotBlank
    @NotNull
    private String description;

    @NotBlank
    @NotNull
    private Status status;

    @NotNull
    @ManyToOne
    @JoinColumn(foreignKey = @ForeignKey(name = "employee_id_fk"))
    private Employee employee;

    @NotNull
    @ManyToOne
    @JoinColumn(foreignKey = @ForeignKey(name = "customer_id_fk"))
    private Customer customer;

    protected Order() {}

    public Order(String description) {
        this.description = description;
        this.status = Status.IN_PROGRESS;
    }
}

И моя конечная точка (это то, что я должен изменить):

    @PostMapping("/orders")
    ResponseEntity<EntityModel<Order>> createOrder(@Valid @RequestBody Order order) {
        order.setStatus(Status.IN_PROGRESS);
        Order newOrder = repository.save(order);

        return ResponseEntity
            .created(linkTo(methodOn(OrderController.class).getOrder(newOrder.getId())).toUri())
            .body(assembler.toModel(newOrder));
    }

Теперь, как мне проверить запросы в этом формате? Ранее, как вы можете видеть, я просто использовал @Valid, и он автоматически проверялся бы, когда конечная точка вызывается для модели Order. Однако, если я создаю DTO, мне придется проверять DTO по той же методологии и дублировать все аннотации из его модели (@NotNull, @NotBlank и т. Д. c.). Может быть, мне следует проверить модель сущностей после сопоставления ее с DTO, но я не знаю, насколько это будет просто и является ли это хорошей практикой проверки запросов. Я также не могу удалить проверки из модели сущностей, потому что я использую Hibernate для сопоставления их с таблицами.

1 Ответ

1 голос
/ 25 апреля 2020

Хорошие вопросы!

Я не думаю, что каждый раз, когда я создаю новый Заказ с помощью запроса POST, я должен заставить клиента отправлять целые объекты Customer и Employee внутри запроса как вложенные объекты. порядка (если я тоже не прав в этом, пожалуйста, дайте мне знать).

Вы правы. Это не потому, что мы можем сохранять биты и байты (как это может выглядеть), а потому, что чем меньше информации вы можете спросить у клиента, тем лучше он получит опыт (будь то внешний интегратор или интерфейсный / задний) -конец заявки в той же компании). Меньшее количество данных для охвата = легче для понимания и меньше места для ошибки. Это также делает ваш API чище с точки зрения дизайна. Можно ли обработать ваш запрос без поля? Тогда его не должно быть в вашем API.

Теперь, как мне проверять запросы в этом формате? Ранее, как вы можете видеть, я просто использовал @Valid, и он автоматически проверялся при вызове конечной точки для модели Order. Однако, если я создаю DTO, мне придется проверять DTO по той же методике и дублировать все аннотации из его модели (@NotNull, @NotBlank, et c.).

Вы также можете использовать @Valid, чтобы запустить проверку DTO внутри контроллера в методе, сопоставленном с конечной точкой. Но, как вы правильно заметили, все проверенные поля в DTO должны быть аннотированы @NotNull, @NotBlank, et c. В качестве решения проблемы «дублирования» вы можете создать базовый класс и определить все проверки в нем и наследовать от него DTO и Entity. Но, пожалуйста, не делайте этого!

Наличие одинаковых полей и правил проверки в DTO и Enity не считается дублированием, поскольку они являются отдельными концепциями, и каждое из них служит своей определенной c цели на своем уровне (DTO - верхний уровень, Entity - чаще всего нижний, уровень данных). Есть много примеров, демонстрирующих это (например, здесь и здесь )

Может быть, я должен проверить модель сущности после сопоставления ее из DTO, но я не знаю, насколько это просто, и является ли это хорошей практикой проверки запросов.

Рекомендуется проверять запрос, и многие проекты следуют ему. В вашем примере это очень просто (прямое отображение из DTO в Entity), но очень часто у вас будет сервисный уровень, который выполняет некоторую бизнес-логику c, прежде чем передать его на уровень данных (даже в вашем примере я рекомендую выйти ваш код от контроллера до уровня обслуживания). Вы не хотите, чтобы неправильно сформированный запрос передавался за пределы контроллера, чтобы обрабатывать его позже с помощью чрезмерных операторов if, нулевых проверок (что приводит к защитному коду, которому трудно следовать и который также подвержен ошибкам).

Еще одно примечание: Вы не должны жертвовать опытом клиента и говорить им или заставлять себя добавить еще два поля, потому что это позволяет иметь один Объект, служащий DTO и Entity, и упрощает разработку.

Последнее примечание: Чтобы отобразить поля из DTO в Entity, вы можете использовать одну из библиотек объектного сопоставления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...