多対多をルート リソースのサブコレクションとして表すことができます。例 /items/1234 と /groups/4567 があります - /items/1234/groups または /groups/4567/items としてグループをサブコレクションとして持つことができます
どちらの方法も等しく有効です。私は通常、 aを使用しPUT
てリレーションシップを設定し、 a を使用しDELETE
てそれを削除するというルートをたどります。これは実際には REST ではないと言う人もいますが、私が使用したシナリオではうまく機能しました。
PUT /items/1234/groups/4567
- アイテム 1234 とグループ 4567 の間の関係を作成します - アイテム 1234 とグループ 4567
DELETE /items/1234/groups/4567
の間の関係を削除します
この投稿は私を大いに助けました。このラストを調べていたら…
RESTful API で多対多の関係を処理する方法は?
更新: ルーティング
したがって、これらのより複雑なシナリオでは、より具体的なルートを単純に使用することになりました。すべてを単一の一般的なルートに詰め込もうとすると、すぐに醜くなる可能性があります。関連する URL が適切なコントローラーとアクションにルーティングされることを確認する一連の単体テストがあります。
// routes
routes.MapHttpRoute(
name: "items.groups",
routeTemplate: "items/{itemId}/groups/{groupId}",
defaults: new { controller = "ItemGroup", groupId = RouteParameter.Optional });
次に、ItemGroupController には Get、Delete、および Put メソッドがあります。このように単体テストを行います...
// unit tests
[Test]
public void PutItemGroup()
{
RoutingResult routingResult = this.GenerateRoutingResult(HttpMethod.Put, "~/items/1234/groups/4567");
Assert.IsNotNull(routingResult);
Assert.AreEqual("ItemGroup", routingResult.Controller);
Assert.AreEqual("Put", routingResult.Action);
Assert.AreEqual("1234", routingResult.RouteData.Values["itemId"]);
Assert.AreEqual("4567", routingResult.RouteData.Values["groupId"]);
}
[Test]
public void GetItemGroups()
{
RoutingResult routingResult = this.GenerateRoutingResult(HttpMethod.Get, "~/items/1234/groups");
Assert.IsNotNull(routingResult);
Assert.AreEqual("ItemGroup", routingResult.Controller);
Assert.AreEqual("GetAll", routingResult.Action);
Assert.AreEqual("1234", routingResult.RouteData.Values["itemId"]);
}
[Test]
public void GetItemGroup()
{
RoutingResult routingResult = this.GenerateRoutingResult(HttpMethod.Get, "~/items/1234/groups/4567");
Assert.IsNotNull(routingResult);
Assert.AreEqual("ItemGroup", routingResult.Controller);
Assert.AreEqual("Get", routingResult.Action);
Assert.AreEqual("1234", routingResult.RouteData.Values["itemId"]);
Assert.AreEqual("4567", routingResult.RouteData.Values["groupId"]);
}
[Test]
public void DeleteItemGroup()
{
RoutingResult routingResult = this.GenerateRoutingResult(HttpMethod.Delete, "~/items/1234/groups/4567");
Assert.IsNotNull(routingResult);
Assert.AreEqual("ItemGroup", routingResult.Controller);
Assert.AreEqual("Delete", routingResult.Action);
Assert.AreEqual("1234", routingResult.RouteData.Values["itemId"]);
Assert.AreEqual("4567", routingResult.RouteData.Values["groupId"]);
}
private RoutingResult GenerateRoutingResult(HttpMethod method, string relativeUrl)
{
HttpConfiguration httpConfiguration = new HttpConfiguration(this.HttpRoutes);
HttpRequestMessage request = new HttpRequestMessage(method, string.Format("http://test.local/{0}", relativeUrl.Replace("~/", string.Empty)));
IHttpRouteData routeData = this.HttpRoutes.GetRouteData(request);
Assert.IsNotNull(routeData, "Could not locate route for {0}", relativeUrl);
this.RemoveOptionalRoutingParameters(routeData.Values);
request.Properties.Add(HttpPropertyKeys.HttpRouteDataKey, routeData);
request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, httpConfiguration);
IHttpControllerSelector controllerSelector = new DefaultHttpControllerSelector(httpConfiguration);
HttpControllerContext controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
{
ControllerDescriptor = controllerSelector.SelectController(request)
};
HttpActionDescriptor actionDescriptor = controllerContext.ControllerDescriptor.HttpActionSelector.SelectAction(controllerContext);
if (actionDescriptor == null)
{
return null;
}
return new RoutingResult
{
Action = actionDescriptor.ActionName,
Controller = actionDescriptor.ControllerDescriptor.ControllerName,
RouteData = routeData
};
}
private void RemoveOptionalRoutingParameters(IDictionary<string, object> routeValueDictionary)
{
int count = routeValueDictionary.Count;
int index1 = 0;
string[] strArray = new string[count];
foreach (KeyValuePair<string, object> keyValuePair in routeValueDictionary)
{
if (keyValuePair.Value == RouteParameter.Optional)
{
strArray[index1] = keyValuePair.Key;
++index1;
}
}
for (int index2 = 0; index2 < index1; ++index2)
{
string key = strArray[index2];
routeValueDictionary.Remove(key);
}
}
private class RoutingResult
{
public string Controller { get; set; }
public string Action { get; set; }
public IHttpRouteData RouteData { get; set; }
}
乾杯、ディーン