2017-04-18 24 views
0

リクエストボディは、のような公式のAPI宣言ページに記述されている使用のプロセス:レトロフィットリクエストボディ:必須項目

@POST("users/new") 
Call<User> createUser(@Body User user); 

Userオブジェクトを作成するためのガイドはありませんが、私はそれを見ることができます想像しますこのような何か:拡張することで

public class User { 
    public String name; 
    public String group; 
} 

、これは、このようなリクエストボディにつながる:

{ 
    "name": string, 
    "group": string 
} 

デフォルトでは、これらのフィールドはオプションです。私はそれらを必要とする最良の方法は何ですか?

+0

あなたはそれを必要としていないようです。リクエスト本体が有効かどうかをサーバーに決定させます。 –

+0

@LyubomyrShaydarivしたがって、手動で検証するのが最善の方法です。私はクエリパラメータが持っている検証に似たもっと直感的な方法、例えば 'javax.validation.constraints @ NotNull'を望んでいました。 – OskarD90

+0

私はリクエストをそのまま送信し、サーバがそれを受け入れるか拒否することを意味します。あるいは、あなたがクライアント側でそれを行う必要がある理由がありますか? –

答えて

1

このような動作を達成する方法はたくさんあります。次のことが可能です。

  • ...あなたはレトロフィット・サービス(ユーザー入力フォームなど)を起動する前に、POST EDになるように、あなたのオブジェクトを検証し、それが高速に失敗してみましょう。
  • ...(あなたがいずれかを持っている場合)あなたのデータ転送は、彼らがされた後、集中管理、オブジェクトをオブジェクト検証...レトロフィット要求コンバータでの集中ごドメインオブジェクトを、検証し、連鎖コンバータ
  • を使用ドメインオブジェクトから変換されて送信されるように準備されました
  • ...サーバーAPIの実装に依存しています。クライアント側での検証は不要です。サーバーロジックを随時複製する必要はありません。サーバーAPIの検証では、より多くのコードを書くなど、これは私がそのコメントであなたに示唆していたものです。

それらが送信される前に、あなた本当にがリクエストボディを検証する必要がある場合は、最初のオプションで行く必要があります。検証を完全に集中化したい場合は、カスタムRetrofitコンバータを実装して、事前検証を実行できます。 (以下のコードでは、Java 8とGoogle Guava、Retrofit 2、Gsonを少し使用していますが、別のコンポーネントで簡単に再作成できます)。

は、これらを考慮してください。

interface IService { 

    @POST("/") 
    Call<String> post(
      @Body User user 
    ); 

} 
final class User { 

    final String name; 
    final String group; 

    User(final String name, final String group) { 
     this.name = name; 
     this.group = group; 
    } 

} 

今、私たちはレトロフィット-ものを実装することができます。次のmockOkHttpClientは任意の要求を消費し、HTTP 200 OK"OK"と応答するモックOkHttpClientです。

private static final OkHttpClient mockOkHttpClient = new OkHttpClient.Builder() 
     .addInterceptor(chain -> new Response.Builder() 
       .request(chain.request()) 
       .protocol(HTTP_1_0) 
       .code(HTTP_OK) 
       .body(ResponseBody.create(MediaType.parse("application/json"), "\"OK\"")) 
       .build() 
     ) 
     .build(); 

それでは、簡単なテストを作成してみましょう:

final Iterable<Retrofit> retrofits = ImmutableList.of(
     getAsIsRetrofit(), 
     getValidatedDomainObjectsRetrofit(), 
     getValidatedDataTransferObjectsRetrofit() 
); 
final User user = new User("user", "group"); 
for (final Retrofit retrofit : retrofits) { 
    final IService service = retrofit.create(IService.class); 
    final String message = service.post(user).execute().body(); 
    System.out.println(message); 
} 

あなたが見ることができるように、それらのそれぞれを実証するための異なる構成でインスタンス化されている3つのレトロフィットインスタンスがあります。

以下のRetrofitインスタンスは、検証そのものを気にしません。そしてこれは私があなたに行くことをお勧めする別の時です:単にあなたが得たものを投稿して、サーバーAPI実装がそれ自体を処理させるようにします。 HTTP 400 Bad Requestなどのような素晴らしい応答を返すAPI実装を考えてみましょう。

private static Retrofit getAsIsRetrofit() { 
    return new Retrofit.Builder() 
      .client(mockOkHttpClient) 
      .baseUrl("http://whatever") 
      .addConverterFactory(GsonConverterFactory.create()) 
      .build(); 
} 

Retrofitインスタンスを検証し、それがGsonやさしい表現に変換(あなたがアプリケーション内のデータ転送オブジェクト変換からドメインオブジェクトがある場合に依存)ですUserオブジェクトを指定:

private static Retrofit getValidatedDomainObjectsRetrofit() { 
    return new Retrofit.Builder() 
      .client(mockOkHttpClient) 
      .baseUrl("http://whatever") 
      .addConverterFactory(new Converter.Factory() { 
       @Override 
       public Converter<?, RequestBody> requestBodyConverter(final Type type, final Annotation[] parameterAnnotations, 
         final Annotation[] methodAnnotations, final Retrofit retrofit) { 
        if (type != User.class) { 
         return null; 
        } 
        final Converter<Object, RequestBody> nextConverter = retrofit.nextRequestBodyConverter(this, type, parameterAnnotations, methodAnnotations); 
        return (Converter<Object, RequestBody>) value -> { 
         if (value instanceof User) { 
          final User user = (User) value; 
          requireNonNull(user.name, "name must not be null"); 
          requireNonNull(user.group, "group must not be null"); 
         } 
         return nextConverter.convert(value); 
        }; 
       } 

      }) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .build(); 
} 

そして、次に出力ストリームに書き込まれる前にデータ転送オブジェクトが検証されます。おそらく最も低レベルのインスタンスです。 requireNonNullはJDK 8の方法で、あなたが@NotNullのような何かをしたい場合は、あなたがあなた自身の注釈プロセッサを実装する、または私の実装のアイデアは無用検討し、インターネットでのこのような実装を見つけることができることを

private static Retrofit getValidatedDataTransferObjectsRetrofit() { 
    final Gson gson = new GsonBuilder() 
      .registerTypeAdapterFactory(new TypeAdapterFactory() { 
       @Override 
       public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) { 
        if (typeToken.getRawType() != User.class) { 
         return null; 
        } 
        final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken); 
        return new TypeAdapter<T>() { 
         @Override 
         public void write(final JsonWriter out, final T value) 
           throws IOException { 
          if (value instanceof User) { 
           final User user = (User) value; 
           requireNonNull(user.name, "name must not be null"); 
           requireNonNull(user.group, "group must not be null"); 
          } 
          delegateTypeAdapter.write(out, value); 
         } 

         @Override 
         public T read(final JsonReader in) 
           throws IOException { 
          return delegateTypeAdapter.read(in); 
         } 
        }; 
       } 
      }) 
      .create(); 
    return new Retrofit.Builder() 
      .client(mockOkHttpClient) 
      .baseUrl("http://whatever") 
      .addConverterFactory(GsonConverterFactory.create(gson)) 
      .build(); 
} 

注意。 :)しかし、私は、現状のアプローチが最も好きだと思います。

関連する問題