Повторное использование DTO для различных типов запросов / ответов против ясности того, что требуется / что должно быть возвращено

Я начал задумываться о том, не попадаю ли я здесь в антипаттерн, поэтому, пожалуйста, посоветуйте лучшие практики.

Я разрабатываю REST API с набором различных конечных точек, и я хотел обернуть параметры запроса и ответа в хороший DTO.

Например, несколько конечных точек:

public async Task<JobStateResponse> GetJobState(JobStateRequest request);
public async Task<JobDownloadRespose> DownloadJob(JobDownloadRequest request);
public async Task<CreateJobResponse> CreateJob(CreateJobRequest request);

Проблема в том, что эти запросы и ответы относительно похожи на DTO, например:

public class JobStateResponse{
    public int TaskId {get;set;}
    public string ExternalId {get;set;}
    public State State {get;set;}
}
public class JobDownloadResponse {
    public int TaskId {get;set;}
    public string ExternalId {get;set;}
    public string JobContent {get;set;}
}

Я думал о создании базового класса для них и наследовании, но в некоторых случаях некоторые свойства могут быть избыточными... Это означает, что методы не ясно указывают, какие параметры необходимы для их работы, чтобы работать нормально.

Я имею в виду, выставляя конечную точку API с параметром DTO, который имеет 7 свойств, но только действительно нуждается в 2 звуках довольно плохо...

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

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

Итак, каков правильный подход для обработки ответа на запрос<>?

РЕДАКТИРОВАТЬ: Относительно флагов "на основе мнения" - я ищу лучшую практику для обработки этого. Я знаю, что это можно сделать несколькими способами, но я хочу избежать противопехотных мин. Кроме того, я должен сказать, что до сих пор очень доволен ответами.

3 ответа

Решение

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

Создайте DTO для каждой конечной точки запроса и отдельное DTO для каждого ответа. В противном случае вам в конечном итоге будет грустно.

Если вы найдете элементы, которые являются общими для нескольких конечных точек, извлеките их в их собственный объект и включите их в обе.

И да, использование наследования здесь было бы неправильно. Придерживайтесь композиционных узоров, и у вас все будет хорошо.

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

Вы определенно хотите разделить DTO для каждой конечной точки на 2 группы: запрос и ответ.

Теперь, говоря о наследовании, вы можете иметь базовый класс Request и базовый класс Response, который будет включать в себя некоторые общие, неспецифические вещи (например, сообщение-оболочку запроса и ответа, в которое вы вставляете свои данные), но вы не хотите смешивать наследование между запросами. и ответная сторона.

Как уже отмечали другие, вначале это немного больше кода, но таким образом вы никогда не попадете в стену. Напротив, их смешивание довольно скоро приведет к тому, что у вас будут огромные рефакторинги, где вы потеряете больше времени и нервов, чем начните с чистого, отдельного способа.

Другие вопросы по тегам