使用请求正文的过程在官方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 :(得分:1)
有很多方法可以实现这种行为。你可以:
POST
,并让它快速失败。如果真的需要在发送之前验证请求正文,您应该使用第一个选项。如果要使验证完全集中,可以实现自定义的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;
}
}
现在我们可以实施Retrofit-stuff。以下mockOkHttpClient
是模拟OkHttpClient
,可以使用HTTP 200 OK
和"OK"
消费任何请求并回复。
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);
}
如您所见,有三个Retrofit实例使用不同的配置进行实例化以演示每个实例。
以下Retrofit
实例不关心验证本身。这是我建议您使用的另一个时间:简单地发布您获得的内容并让服务器API实现自己处理它。考虑API实现以返回好的响应,如HTTP 400 Bad Request
等。
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();
}
下一个在将数据传输对象写入输出流之前验证它们。可能是这里最低级别的实例。
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();
}
请注意requireNonNull
是JDK 8方法,如果你想要@NotNull
之类的东西,你可以实现自己的注释处理器,或者在互联网上找到这样的实现,因为我的实现思路没用。 :)但是,我认为你最喜欢的是as-is方法。