在 Limyee 电商平台中创建新内容、应用程序/或其他自定义数据和服务时,您可以通过 REST 公开这些服务来进行外部集成。这提供了极大的灵活性,允许外部集成访问您的定制数据。
每当您希望使 Limyee 电商平台外部的应用程序能够与您的自定义数据进行交互时,都应通过 REST 公开数据。这也可以在 Limyee 电商平台界面中使用,用于小组件的 AJAX 操作。此外,如果要提供更广泛的响应,或将响应限制为特定字段,则可以将一个或多个进程 API 包装到新的 REST 端点中。
我们的示例为实体提供推荐的标准 REST 端点集:创建、更新、删除、获取和列表。如果你的方案不需要它们,则不需要全部使用它们。
必需引用的 DLL:
该过程的第一步是编写自定义数据或服务以创建 REST 端点。虽然本文重点介绍自定义数据,但您也可以创建一个自定义对象来存储从一个或多个进程 API 检索的平台数据并返回这些数据。在此示例中,我们将重点介绍一个名为“Dog”的自定义类。
using System;
namespace Samples
{
public class Dog
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Breed { get; set; }
}
}
在本演示中,我们假设存在一个支持服务来对此对象执行 CRUD 操作。我们将其称为 DogService,并假定其方法单独采用所有必需参数,并将所有可选参数分组到 Dog<MethodName>Options 类中。这与进程 API 的模式相同。
实现 IRestEndpoints 需要一个 Register 方法,该方法为您提供了一个用于注册 REST 路由的控制器。路由将始终以标准的 Limyee 电商平台 REST URL(<siteurl> + “/api/{version}”)开头,我们将定义 URL 的其余部分,包括每个所需方法的版本。IRestEndpoints 也是从 IPlugin 派生出来的,所以你还需要实现基本的 IPlugin 接口。
端点的声明实际上相当简单。参数为:
public void Register(IRestEndpointController restRoutes)
{
restRoutes.Add(1, "dogs", new { resource = "dog", action = "create" }, null, HttpMethod.Post, CreateDog);
restRoutes.Add(1, "dog/{id}", new { resource = "dog", action = "update" }, null, HttpMethod.Put, UpdateDog);
restRoutes.Add(1, "dog/{id}", new { resource = "dog", action = "delete" }, null, HttpMethod.Delete, DeleteDog);
restRoutes.Add(1, "dog/{id}", new { resource = "dog", action = "show" }, null, HttpMethod.Get, GetDog);
restRoutes.Add(1, "dogs", new { resource = "dog", action = "list" }, null, HttpMethod.Get, ListDogs);
}
声明路由 URL 类似于 MVC 路由,因为路由可能会意外重叠,从而完全隐藏某些路由。您需要确保不会发生这种情况,以便所有方法都可用,并且对这些方法的调用不会路由到错误的内部方法。您可以通过 HTTP 方法、参数约束和路由本身的组合来区分路由。关于重叠路由,需要注意和避免的几种情况:
每个 REST 方法都接受一个 IRestRequest 对象,并返回一个实现 IRestResponse 的对象。请求存储数据有两个主要组件:PathParameters 和 Form。PathParameters 的内容是从 url 路径解析的内容,包括查询字符串,Form 的内容是从请求正文中解析的。您还可以选择直接从 IRestRequest.Request.QueryString 访问查询字符串。
IRestResponse 接口相当通用,提供位置允许您放置数据对象,以便可以将其序列化到 HTTP 响应中。它还需要数据对象的名称(对于最外层的序列化实体),并提供列表访问响应中的错误字符串。
用于执行每个操作的函数是单独声明的。首先,我们必须创建一个实现 IRestResponse 的 响应对象,以便我们可以以已知格式发送数据。
[XmlRoot(ElementName = "Response")]
[RestAction(RestAction.Show, "achievement")]
public class DogResponse : IRestResponse
{
private Dog _dog;
public Dog Dog
{
get { return _dog; }
set
{
_dog = value;
}
}
public string Name { get { return "Dog"; } }
public object Data { get { return _dog; } }
public string[] Errors { get; set; }
}
当我们要添加对象的实例时,将使用 Create。在此示例中,添加狗只需要名称,因此我们检查该名称,如果缺少,则提前返回错误。可以在此处进行其他检查,例如,必需的参数需要是整数。检查可选参数更容易,我们只需要将其分配给选项对象(如果它确实存在)。收集到所需的全部信息后,您可以调用内部服务,执行必要的操作,并在 REST 响应中返回相关信息。重要的是要将内部调用包装在 try...catch 代码块中,因此您可以确保返回的请求是 REST 响应,而不是 ASP.net 错误页。如果缺少必需的参数或未满足要求,或者内部出现其他问题,则可能会返回错误响应(建议为此使用 IUserRenderableException)。如果包含全部必需的参数,则可以分析每个参数,然后将其与基础内部服务一起使用以执行请求的操作。
public IRestResponse CreateDog(IRestRequest request)
{
var response = new DogResponse();
if (request.Form["Name"] == null)
{
response.Errors = new[] { "Name is required" };
return response;
}
var name = request.PathParameters["Name"].ToString();
var options = new DogCreateOptions();
if (request.Form["Breed"] != null)
options.Breed = request.Form["Breed"];
try
{
var createdDog = DogService.Create(name, options);
response.Dog = createdDog;
}
catch (Exception ex)
{
response.Errors = new[] { "Error: '{0}'", ex.ToString() };
}
return response;
}
Update 使用最初从 Create 返回的 Id 来查找对象,这允许所有其他参数都是可选的,并且仅在指定时更改。
public IRestResponse UpdateDog(IRestRequest request)
{
var response = new DogResponse();
if (!request.PathParameters.ContainsKey("Id"))
{
response.Errors = new[] { "Id is required" };
return response;
}
var id = Guid.Parse(request.PathParameters["Id"].ToString());
var options = new DogUpdateOptions();
if (request.Form["Name"] != null)
options.Name = request.PathParameters["Name"].ToString();
if (request.Form["Breed"] != null)
options.Breed = request.PathParameters["Breed"].ToString();
try
{
var createdDog = DogService.Update(id, options);
response.Dog = createdDog;
}
catch (Exception ex)
{
response.Errors = new[] { "Error: '{0}'", ex.ToString() };
}
return response;
}
Delete 只需要对象的 ID 即可将其从数据库中删除。
public IRestResponse DeleteDog(IRestRequest request)
{
var response = new DefaultRestResponse();
if (!request.PathParameters.ContainsKey("Id"))
{
response.Errors = new[] { "Id is required" };
return response;
}
var id = Guid.Parse(request.PathParameters["Id"].ToString());
try
{
DogService.Delete(id);
}
catch (Exception ex)
{
response.Errors = new[] { "Error: '{0}'", ex.ToString() };
}
return response;
}
Get 也只需要 Id 即可返回完整对象。
public IRestResponse GetDog(IRestRequest request)
{
var response = new DogResponse();
var options = new DogGetOptions();
if (!request.PathParameters.ContainsKey("Id"))
{
response.Errors = new[] { "Id is required" };
return response;
}
options.Id = Guid.Parse(request.PathParameters["Id"].ToString());
try
{
var dog = DogService.Get(options);
response.Dog = dog;
}
catch (Exception ex)
{
response.Errors = new[] { "Error: '{0}'", ex.ToString() };
}
return response;
}
List 在从中返回的内容而言,是最灵活的方法,因为不包含必需的参数,可使用其他可选参数用于返回自定义列表。
public IRestResponse ListDogs(IRestRequest request)
{
var response = new DefaultRestResponse();
var options = new DogListOptions();
if (request.PathParameters.ContainsKey("Name"))
options.Name = request.PathParameters["Name"].ToString();
if (request.PathParameters.ContainsKey("Breed"))
options.Breed = request.PathParameters["Breed"].ToString();
if (request.PathParameters.ContainsKey("SortBy"))
options.SortBy = request.PathParameters["SortBy"].ToString();
if (request.PathParameters.ContainsKey("SortOrder"))
options.SortOrder = request.PathParameters["SortOrder"].ToString();
if (request.PathParameters.ContainsKey("PageSize"))
options.PageSize = Int32.Parse(request.PathParameters["PageSize"].ToString());
if (request.PathParameters.ContainsKey("PageIndex"))
options.PageIndex = Int32.Parse(request.PathParameters["PageIndex"].ToString());
try
{
var dogs = DogService.List(options);
response.Name = "Dogs";
response.Data = dogs;
}
catch (Exception ex)
{
response.Errors = new[] { "Error: '{0}'", ex.ToString() };
}
return response;
}
有关调用 REST 端点的信息,请参阅 REST API:发起请求。