7

ジェネリック型の応答オブジェクトのドキュメントに関して、Swagger の ServiceStack 実装に問題があります。厳密に型指定された応答オブジェクトは正しく文書化されて表示されますが、ジェネリック型のオブジェクトが応答として使用されると、文書化は不正確になり、誤解を招きます。

DTO を要求する

[Route("/users/{UserId}", "GET", Summary = "Get a specific User Profile")]
public class GetUser : IReturn<ServiceResponse<UserProfile>>
{
    [ApiMember(Description = "User Id", ParameterType = "path", IsRequired = true)]
    public int UserId { get; set; }
}

応答 DTO

public class ServiceResponse<T> : IServiceResponse<T>
{
    public IList<string> Errors { get; set; }
    public bool Successful { get; set; }
    public string Message { get; set; }
    public string StackTrace { get; set; }
    public T Data { get; set; }

    public ServiceResponse()
    {
        Errors = new List<string>();
    }
}

応答 DTO タイプ

public class UserProfile : RavenDocument
{
    public UserProfile()
    {
        Races = new List<UserRace>();
        Workouts = new List<Workout>();
    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string DisplayName { get; set; }
    public DateTime? BirthDate { get; set; }
    public Gender? Gender { get; set; }
    public string UltracartPassword { get; set; }
    public string UltracartCartId { get; set; }

    [UniqueConstraint]
    public string Email { get; set; }

    public string ImageUrl { get; set; }

    public FacebookUserInfo FacebookData { get; set; }
    public GoogleUserInfo GoogleData { get; set; }

    public DateTime CreatedOn { get; set; }
    public DateTime? LastUpdated { get; set; }
    public UserAddress ShippingAddress { get; set; }
    public UserAddress BillingAddress { get; set; }
    public IList<UserRace> Races { get; set; }
    public IList<Workout> Workouts { get; set; }
}

例は非常に簡単です。ハックや巧妙なことは何もありませんが、これは私が Swagger からすぐに取得できるサンプル ドキュメントです。

Swagger の例

ご覧のとおり、ジェネリック型は正しく文書化されておらず、代わりに他の型が使用されています。すべての応答に同じ ServiceResponse ラッパーを使用しているため、これは全体的に発生しています。

4

1 に答える 1

2

お気づきのとおり、ServiceStack swagger プラグインは現在、ジェネリック型をきれいに処理しようとはしていません。より適切に機能する単純な代替手段は、ジェネリック型の具体的なサブクラスを作成することです。例えば:

public class UserProfileResponse : ServiceResponse<UserProfile> { ... }

public class GetUser : IReturn<UserProfileResponse> ...

これは、Swagger によって適切に処理される必要があります。

ジェネリック型が常に ServiceStack DTO に適しているとは限らないことがわかりました。StackOverflowに関する多くの議論 (たとえば、ここここここ) で、これについて説明し、具象型と一般的に継承を回避することが ServiceStack DTO にとって良い考えである理由を見つけることができます。

DRY 原則を DTO の要求/応答に適用したいという誘惑に打ち勝つには努力が必要です。ジェネリックと継承は、ジェネリック メソッドまたは基本クラスが具象型の詳細を知る必要がない、ジェネリックで再利用可能な方法でアルゴリズムの実装を容易にする言語機能であると私は考えています。DTO は、継承またはジェネリックの機会のように見える共通の構造を表面的に持っている場合がありますが、この場合、各 DTO の実装とセマンティクスは具体的な使用法ごとに異なるため、各要求/応答メッセージの詳細は明示的に定義する必要があります。

于 2014-01-06T15:13:32.453 に答える