技术经验解读:使用Refit框架访问REST接口

简介: 技术经验解读:使用Refit框架访问REST接口

Refit 是一个类型安全的 REST 开源库,是一套基于 RESTful 架构的 .NET 客户端实现,内部使用 HttpClient 类封装,可通过 Refit 更加简单安全地访问 Web API 接口,要使用 Refit 框架,只需要在项目中通过 NuGet 包安装器安装即可。


Install-Package refit


使用方法很简单:


public interface IGitHubApi


{


【Get("/users/{userid}")】


Task GetUser(string userid);


}


以上方法定义一个 REST API 接口,该接口定义了 GetUser 函数,该函数通过 HTTP GET 请求去访问服务器的 /users/{userid} 路径并把返回的结果封装为 User 对象返回,其中 URL 路径中 {userid} 的值为 GetUser 函数的 userid 参数取值,然后,通过 RestService 类生成 IGitHubApi 的代理实现,通过代理直接调用 Web API 接口。


var gitHubApi = RestService.For("");


var octocat = await gitHubApi.GetUser("xcode");


API Attributes特性


通过 Attribute 特性标记,指定请求方法和相对 URL 地址,内置支持 Get、Post、Put、Delete 和 Head 方法。


【Get("/users/list")】


也可以在 URL 中指定查询参数:


【Get("/users/list?sort=desc")】


方法中的 URL 地址可以使用占位符,占位符是由 {} 包围的字符串,如果函数参数与 URL 路径中的占位符名称不同,可使用 AliasAs 指定别名。


【Get("/group/{id}/users")】


Task

值得注意的是,参数名称和 URL 参数占位符不区分大小写,如果一个函数参数未被 URL 占位符所使用,那么它将自动被当作 QueryString 查询字符串来使用


【Get("/group/{id}/users")】


Task

当我们调用 GroupList 方法时,相当于请求 "/group/4/users?sort=desc"这个地址,其中 sort 参数被当作 GET 参数自动使用。


Dynamic Querystring Parameters


函数参数可传递对象,对象的字段属性将被自动追加到 Querystring 查询字符串。


public class MyQueryParams


{


【AliasAs("order")】


public string SortOrder { get; set; }


public int Limit { get; set; }


}


【Get("/group/{id}/users")】


Task

【Get("/group/{id}/users")】


Task

param.SortOrder = "desc";


param.Limit = 10;


GroupList(4, param)



GroupListWithAttribute(4, param)



Collections as Querystring parameters


除了支持对象参数外,还是支持集合参数,下面是使用示例:


【Get("/users/list")】


Task Search(【Query(CollectionFormat.Multi)】int【】 ages);


Search(new 【】 {10, 20, 30})



【Get("/users/list")】


Task Search(【Query(CollectionFormat.Csv)】int【】 ages);


Search(new 【】 {10, 20, 30})



Body内容


通过使用 BodyAttribute 特性,将函数参数追加到 HTTP 请求的 Body 部分。


【Post("/users/new")】


Task CreateUser(【Body】 User user);


根据参数的类型,提供 Body 数据有四种可能:如果类型为 Stream 流类型,则内容将通过 StreamContent 流式传输。如果类型是 String 字符串类型,则该字符串将直接用作内容。如果参数具有 【Body(BodySerializationMethod.UrlEncoded)】 属性,内容将被 URL 编码后使用。对于以上除外的其它类型,对象将被序列化为 JSON 传输。


JSON内容


基于 JSON 的请求和响应,内部使用 JSON.NET 框架进行序列化和反序列化,默认情况下,Refit 框架将使用 JsonConvert.DefaultSettings 来配置序列化器的行为:


JsonConvert.DefaultSettings =


() => new JsonSerializerSettings() {


ContractResolver = new CamelCasePropertyNamesContractResolver(),


Converters = {new StringEnumConverter()}


};


// Serialized as: {"day":"Saturday"}


await PostSomeStuff(new { Day = DayOfWeek.Saturday });


因为静态属性 DefaultSettings 是全局设置,它会影响整个应用程序,有些时候,我们希望对某些 API 请求使用特定序列化设置,可以使用 RefitSettings 来指定。


var gitHubApi = RestService.For("",


new RefitSettings {


JsonSerializerSettings = new JsonSerializerSettings {


ContractResolver = new SnakeCasePropertyNamesContractResolver()


}


});


var otherApi = RestService.For("",


new RefitSettings {


JsonSerializerSettings = new JsonSerializerSettings {


ContractResolver = new CamelCasePropertyNamesContractResolver()


}


});


对象属性的序列化行为可以通过 JSON.NET 框架本身的 JsonPropertyAttribute 特性定制:


public class Foo


{


// Works like 【AliasAs("b")】 would in form posts (see below)


【JsonProperty(PropertyName="b")】


public string Bar { get; set; }


}


Form posts


对于采用表单提交数据(application/x-www-form-urlencoded)的 API 接口,使用 BodySerializationMethod.UrlEncoded 初始化 BodyAttribute 特性,参数可以是一个 IDictionary 字典。


public interface IMeasurementProtocolApi


{


【Post("/collect")】


Task Collect(【Body(BodySerializationMethod.UrlEncoded)】 Dictionary[span style="color: rgba(0, 0, 255, 1)">string, object

}


var data = new Dictionary[span style="color: rgba(0, 0, 255, 1)">string, object

{"v", 1},


{"tid", "UA-1234-5"},


{"cid", new Guid("d1e9ea6b-2e8b-4699-93e0-0bcbd26c206c")},


{"t", "event"},


};


// Serialized as: v=1&tid=UA-1234-5&cid=d1e9ea6b-2e8b-4699-93e0-0bcbd26c206c&t=event


await api.Collect(data);


通过表单提交传递数据,也可以是任何对象,对象的所有公开属性和字段将被序列化,可使用 AliasAs 指定别名:


public interface IMeasurementProtocolApi


{


【Post("/collect")】


Task Collect(【Body(BodySerializationMethod.UrlEncoded)】 Measurement measurement);


}


public class Measurement


{


// Properties can be read-only and 【AliasAs】 isn't required


public int v { get { return 1; } }


【AliasAs("tid")】


public string WebPropertyId { get; set; }


【AliasAs("cid")】


public Guid ClientId { get; set; }


【AliasAs("t")】


public string Type { get; set; }


public object IgnoreMe { private get; set; }


}


var measurement = new Measurement {


WebPropertyId = "UA-1234-5",


ClientId = new Guid("d1e9ea6b-2e8b-4699-93e0-0bcbd26c206c"),


Type = "event"


};


// Serialized as: v=1&tid=UA-1234-5&cid=d1e9ea6b-2e8b-4699-93e0-0bcbd26c206c&t=event


await api.Collect(measurement);


设置静态请求头


您可以使用 HeadersAttribute 特性设置一个或多个 HTTP 静态请求标头:


【Headers("User-Agent: Awesome Octocat App")】


【Get("/users/{user}")】


Task GetUser(string user);


也可以通过将 HeadersAttribute 特性应用于接口,这将影响该接口中的所有请求方法:


【Headers("User-Agent: Awesome Octocat App")】


public interface IGitHubApi


{


【Get("/users/{user}")】


Task GetUser(string user);


【Post("/users/new")】


Task CreateUser(【Body】 User user);


}


设置动态请求头


如果请求头需要在运行时设置,则可以通过将 HeaderAttribute 特性应用到函数参数,从而为请求头添加动态值。


【Get("/users/{user}")】


Task GetUser(string user, 【Header("Authorization")】 string authorization);


// Will add the header "Authorization: token OAUTH-TOKEN" to the request


var user = await GetUser("octocat", "token OAUTH-TOKEN");


授权(动态请求头)


标头最常见的用途是授权,今天,大多数 API 都使用 oAuth 协议通过访问令牌授权,申请访问令牌,即可访问 API 接口,访问令牌到期后需要刷新令牌,取得更长寿命的令牌,封装这些令牌的操作,可通过自定义 HttpClientHandler 来实现:


class AuthenticatedHttpClientHandler : HttpClientHandler


{


private readonly Funcstring getToken;


public AuthenticatedHttpClientHandler(Funcstring getToken)


{


if (getToken == null) throw new ArgumentNullException(nameof(getToken));


this.getToken = getToken;


}


protected //代码效果参考:http://www.jhylw.com.cn/112822701.html

override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

{


// See if the request has an authorize header


var auth = request.Headers.Authorization;


if (auth != null)


{


var token = await getToken().ConfigureAwait(false);


request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, token);


}


return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);


}


}


虽然 HttpClient 包含几乎相同的方法签名, 但使用方式不同,HttpClient.SendAsync 没有被改装,必须改为修改 HttpClientHandler,像这样使用:


class //代码效果参考:http://www.jhylw.com.cn/285424335.html

LoginViewModel

{


AuthenticationContext context = new AuthenticationContext(...);


private async Task[span style="color: rgba(0, 0, 255, 1)">string

{


// The AcquireTokenAsync call will prompt with a UI if necessary


// Or otherwise silently use a refresh token to return


// a valid access token


var token = await context.AcquireTokenAsync("", "clientId", new Uri(""));


return token;


}


public async void LoginAndCallApi()


{


var api = RestService.For(new HttpClient(new AuthenticatedHttpClientHandler(GetToken)) { BaseAddress = new Uri("

相关文章
|
6天前
|
存储 缓存 Linux
【实战指南】嵌入式RPC框架设计实践:六大核心类构建高效RPC框架
在先前的文章基础上,本文讨论如何通过分层封装提升一个针对嵌入式Linux的RPC框架的易用性。设计包括自动服务注册、高性能通信、泛型序列化和简洁API。框架分为6个关键类:BindingHub、SharedRingBuffer、Parcel、Binder、IBinder和BindInterface。BindingHub负责服务注册,SharedRingBuffer实现高效数据传输,Parcel处理序列化,而Binder和IBinder分别用于服务端和客户端交互。BindInterface提供简单的初始化接口,简化应用集成。测试案例展示了客户端和服务端的交互,验证了RPC功能的有效性。
123 0
|
21天前
|
SQL 缓存 测试技术
RESTful API设计的最佳实践:构建高效、可维护的Web服务接口
【6月更文挑战第11天】构建高效、可维护的RESTful API涉及多个最佳实践:遵循客户端-服务器架构、无状态性等REST原则;设计时考虑URL结构(动词+宾语,使用标准HTTP方法)、使用HTTP状态码、统一响应格式及错误处理;确保数据安全(HTTPS、认证授权、输入验证);实施版本控制;并提供详细文档和测试用例。这些实践能提升Web服务接口的性能和质量。
|
2月前
|
消息中间件 缓存 算法
构建高效的后端API:优化方法与实践
随着互联网技术的迅速发展,构建高效的后端API已成为现代软件开发中的重要挑战。本文将探讨一些优化方法与实践,以帮助开发人员提高后端API的性能和可靠性。我们将讨论如何通过缓存、异步处理、数据库优化以及代码优化等方式来提升后端API的响应速度和吞吐量,从而为用户提供更好的体验。
|
2月前
|
缓存 安全 API
构建高效可扩展的RESTful API:后端架构的艺术
【4月更文挑战第25天】 在数字化时代的浪潮中,一个稳定、高效且易于扩展的后端系统是企业成功的关键。本文将探讨如何构建一个满足现代业务需求的RESTful API。我们将深入分析关键设计原则,如模块化、服务分层、缓存策略以及数据库优化,并讨论这些原则如何融入实际开发流程中。通过具体案例和最佳实践,我们的目标是为读者提供一套实用的工具和方法,以支持他们自己的后端开发工作。
|
11月前
|
缓存 算法 安全
这才叫 API 接口设计!
一家公司的每个系统都会有各种各样的接口,但是大部分公司,特别是传统行业的公司的所谓接口文档更多是当每个系传统的 word 文本格式,这种传统的格式有着人尽皆知的痛点: 1. 维护不及时; 2. 与代码不同步; 3. 归档后“便束之高阁”; 4. 接口文档跟代码没有互动; 5. 文本检索无法建立全局搜索,需要额外借助工具。 为了解决上述的问题,需要建立一套行之有效的接口管理体系,该体系的目标是: 1. 能够进行接口文档管理,作为后续的接口治理的其中一部分; 2. 能作为接口测试的平台,这样能保证接口跟代码是同步的; 3. 支持文本检索。
|
10月前
|
JSON 程序员 API
以程序员视角讲述关于api数据接口的应用
作为一名程序员,API数据接口是我们日常工作中不可或缺的一部分。API,即Application Programming Interface,应用程序编程接口,是一种用于访问特定软件包或服务的预定义函数和过程。通过API,我们可以从各种数据源获取数据,并将其用于构建应用程序、网站或其他数字工具。
|
11月前
|
前端开发 API
前端学习笔记202305学习笔记第三十一天-什么是mvc-c层api 前后端联动3
前端学习笔记202305学习笔记第三十一天-什么是mvc-c层api 前后端联动3
45 0
|
12月前
|
存储 JSON 数据挖掘
探索API接口:从概念到实践
在当今数字化时代,API(Application Programming Interface)接口成为了各种应用程序之间实现数据交互和功能集成的关键。无论是开发一个网站、构建一个移动应用还是进行数据分析,了解如何调用API接口是必不可少的技术。
|
XML JSON 安全
API接口的技术的概念
当今互联网技术的发展越来越快,越来越多的网站和应用程序需要获取外部数据来提供更好的服务和用户体验,这就需要使用API接口。本文将会对API接口的概念、类型以及如何调用API接口进行简要介绍。
|
运维 前端开发 数据可视化
API 低代码开发:接口大师,一套开发、管理和提供接口的产品框架(三)
API 低代码开发:接口大师,一套开发、管理和提供接口的产品框架
158 1
API 低代码开发:接口大师,一套开发、管理和提供接口的产品框架(三)