Повторное использование 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, который будет включать в себя некоторые общие, неспецифические вещи (например, сообщение-оболочку запроса и ответа, в которое вы вставляете свои данные), но вы не хотите смешивать наследование между запросами. и ответная сторона.
Как уже отмечали другие, вначале это немного больше кода, но таким образом вы никогда не попадете в стену. Напротив, их смешивание довольно скоро приведет к тому, что у вас будут огромные рефакторинги, где вы потеряете больше времени и нервов, чем начните с чистого, отдельного способа.