网络请求只会用Retrofit? 外国人已经在用Apollo Graphql了,与外国人请求合影,结果来到新公司发现就这么
投稿于 被查看 39634 次 评论:141
网络请求只会用Retrofit? 外国人已经在用Apollo Graphql了,与外国人请求合影,结果来到新公司发现就这么
用URL定位资源,用HTTP动词(GET,POST,DELETE,PUT)描述操作
REST的主体是资源,比如网络上的一张图片,一段文字,一个视频,一些实际存在的东西,而URL就是用来指向这个资源的,比如:
https://www.baidu.com/user
这个api一看就是用来对user资源的操作,这里使用名词来指定资源,没有涉及操作相关的声明,为啥呢?因为基本的操作有增删改查,如果你不用restful的话,就会产生四个接口:
https://www.baidu.com/add_user https://www.baidu.com/update_user https://www.baidu.com/delete_user https://www.baidu.com/query_user
GET:对应查询操作 POST:对应增加操作 DELETE:对应删除操作 PUT:对应更新操作
看http url就知道要什么 看http method就知道干什么 看http status code就知道结果如何
200 OK,请求成功。成功的含义取决于HTTP方法 201 Created,该请求已成功,并因此创建了一个新的资源。这通常是在POST请求,或是某些PUT请求之后返回的响应 204,OK,资源删除成功 304 Not Modified,资源没有更新,客户端可以使用缓存 400 Bad Request,有两种情况:1.语义有误,当前请求无法被服务器理解;2.请求参数有误 401 Unauthorized,当前请求需要用户验证 403 Forbidden,服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助 404 Not Found,请求失败,请求所希望得到的资源未被在服务器上发现 414 URI Too Long,请求的URI 长度超过了服务器能够解释的长度,通常的情况包括:本应使用POST方法的表单提交变成了GET方法,导致查询字符串(Query String)过长 500 Internal Server Error,服务器遇到了不知道如何处理的情况 501 Not Implemented,此请求方法不被服务器支持且无法被处理。只有GET和HEAD是要求服务器支持的
一个请求对应一个资源,那么在一些网络请求比较多的页面就会带来比较大的负担,通常情况下应用的首页会承载比较多的内容,这样应用一打开,同时会有很多网络请求发送出去,在获取响应的时候就会带来比较复杂的处理,最明显的就是菊花(loading动画)什么时候该消失; 还有一个比较恶心的情况就是,一些api接口,在设计后它的参数和返回值就会确定,如果哪一天由于设计或者业务变动,需要修改接口字段或者返回值,这时候要是改动这个接口,新版本app是能用,但是老版本的app调用这个接口可能就会产生错误(总不能每次都强制用户升级吧),严重的直接app出现崩溃;不修改原接口,就得增加新的接口; 最烦的就是要维护接口文档了,在漫长的开发过程中,需要时刻根据接口变化去更新api文档,这个痛大家应该都懂。
在graphql里面,之前的多个请求这时候会变成一个请求,这样首页之前要同时调用四个接口,现在只需要调用一个接口就行了,再也不用担心菊花的问题了; 同时graphql里的字段和参数都可以自定义,之前是服务端定义好客户端传什么,返回什么给客户端;现在反过来了,客户端想传什么字段,需要哪些返回值由自己定义,这样api接口就十分灵活了,这样新版本想修改接口只需要增加字段就行了,不需要改动已存在的字段,再也不用担心版本兼容问题了; graphql还可以生成接口文档并支持导出,完美解决你的烦恼
dependencies { classpath 'com.apollographql.apollo:apollo-gradle-plugin:1.2.1' }
第二步:接下来在app module的build.gradle里添加插件依赖和库依赖,记住插件依赖一定要在Android插件后面:
apply plugin: 'com.apollographql.android' dependencies { implementation 'com.apollographql.apollo:apollo-runtime:1.2.1' }
dependencies { implementation ('com.apollographql.apollo:apollo-rx2-support:1.2.1') implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' }
dependencies { compileOnly 'org.jetbrains:annotations:13.0' testCompileOnly 'org.jetbrains:annotations:13.0'//可选 }
在app module下的src/main下创建一个与你的java文件夹相同级别的文件夹,我把它命名为graphql,虽然官方说随便命名,但实际会有一些错误,所以还是用这个名字吧,然后再新建一个类似与com/mango/apollo的三层目录 添加一个schema.json文件到刚才的目录下,这个名字不要改,定死了就这个;后端在部署成功后,会自动生成schema.json文件,是用来描述你的 GraphQL API、所有字段和输入参数等信息的文件,这个文件有点恐怖,即使很简单的一个接口,也能有几十k 添加一个以.graphql为后缀的文件,名字你可以自己命名,它是一个GraphQL 查询(query)文件,这些查询会被 Apollo codegen 用来生成返回数据的数据结构,最重要的是你也可以在里面自定义查询方法,包括新建.graphql文件
query FeedQuery($type: FeedType!, $limit: Int!) { feedEntries: feed(type: $type, limit: $limit) { id repository { ...RepositoryFragment } postedBy { login } } } fragment RepositoryFragment on Repository { name full_name owner { login } }
query FeedQuery($type: FeedType!, $limit: Int!)
query:表示操作类型是query,也就是查询的意思;还有其它的类型比如mutation(表示增删改的意思) 或 subscription,描述你打算做什么类型的操作。操作类型是必需的,除非你使用查询简写语法 FeedQuery:表示操作名称,是你的操作的有意义和明确的名称 $ type: FeedType!:使用$符号定义变量,变量名称是type,变量类型是FeedType,加一个!意思非空
feedEntries: feed(type: $type, limit: $limit)
eedEntries:是feed的别名,最终返回体名就是feedEntries feed:如果没有定义别名,那么返回体名就是feed type: $ type:接受的参数,参数名是type,值是上面定义的变量$type
{ id repository { ...RepositoryFragment } postedBy { login } }
id,repository,postedBy:这几个都是字段,至于最终返回的数据中字段对应的类型是啥由服务端决定,比如id这个字段,返回的可能是string,也可能是int repository字段指向一个Object类型,实际类型是RepositoryFragment,它的定义如
fragment RepositoryFragment on Repository { name full_name owner { login } }
OkHttpClient okHttpClient = new OkHttpClient.Builder() .build(); ApolloClient apolloClient = ApolloClient.builder() .serverUrl(BASE_URL) .okHttpClient(okHttpClient) .build();
第六步:发起请求。使用apollo构建请求和使用okhttp有点类似,还记得在okhttp里如何发起一个请求吗?是不是构建一个Request,然后实例化一个Call,最后发起请求;在apollo里也是这样。
//Limit 和 Type是我们graphQL 查询中的动态参数,在.graphql文件里定义的 FeedQuery feedQuery = FeedQuery .builder() .limit(10) .type(FeedType.HOT) .build(); ApolloQueryCall<FeedQuery.Data> queryCall = apolloClient.query(feedQuery); queryCall.enqueue(new ApolloCall.Callback<FeedQuery.Data>() { @Override public void onResponse(@NotNull Response<FeedQuery.Data> response) { FeedQuery.Data data = response.data(); List<FeedQuery.FeedEntry> feedEntries = data.feedEntries(); for (FeedQuery.FeedEntry feedEntry : feedEntries) { Log.i("MainActivity",""+feedEntry.toString()); } } @Override public void onFailure(@NotNull ApolloException e) { Log.i("MainActivity","onFailure " + e.getMessage()); } });
feedEntries={ id = 105, repository = Repository { fragments = Fragments { repositoryFragment = RepositoryFragment { name = pairhub, full_name = pairhub / pairhub, owner = Owner { login = pairhub } } } }, postedBy = PostedBy { login = gustavlrsn } }
FeedQuery feedQuery = FeedQuery .builder() .limit(10) .type(FeedType.HOT) .build(); Rx2Apollo.from(apolloClient.query(feedQuery)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new DefaultObserver<Response<FeedQuery.Data>>(){ @Override public void onNext(Response<FeedQuery.Data> dataResponse) { FeedQuery.Data data = dataResponse.data(); List<FeedQuery.FeedEntry> feedEntries = data.feedEntries(); for (FeedQuery.FeedEntry feedEntry : feedEntries) { Log.i("MainActivity","feedEntry:"+feedEntry.toString()); } } @Override public void onError(Throwable e) { Log.i("MainActivity","onError " + e.getMessage()); } @Override public void onComplete() { } });
ApolloCall<FeedQuery.Data> apolloCall = apolloClient.query(query); Observable<Response<FeedQuery.Data>> observable = Rx2Apollo.from(apolloCall); ApolloPrefetch<FeedQuery.Data> apolloPrefetch = apolloClient.prefetch(query); Completable completable = Rx2Apollo.from(apolloPrefetch);
Disposable disposable = Rx2Apollo.from(query).subscribe(); disposable.dispose();
用户评论