Дизайн маршрутизации веб-API asp.net (несколько маршрутов)

В настоящее время я разрабатываю API REST с веб-API ASP.NET.

Я хочу предоставить такие методы (методы http не имеют значения - должны работать для всех):

  • /API/клиент
  • /api/client/CID1234 (CID1234 = идентификатор)
  • /api/client/CID1234/заказы (заказы = действие)

Проблема в том, что Id должен быть необязательным - /api/client может возвращать список клиентов Action также должен быть необязательным - в одном случае я хочу получить конкретного клиента и в другом случае я хочу выполнить определенное действие на этом клиенте. (стиль RPC)

Я не думаю, что могу использовать ограничения, потому что «идентификаторы», которые я использую, выглядят совсем по-другому.

Этот подход не сработал:

config.Routes.MapHttpRoute(
            name: "RpcStyleApi",
            routeTemplate: "rest/{controller}/{action}",
            defaults: new { action = RouteParameter.Optional, id = RouteParameter.Optional }
        );

Этот подход также не сработал:

config.Routes.MapHttpRoute(
            name: "RpcStyleApi",
            routeTemplate: "rest/{controller}/{action}"
        );

        config.Routes.MapHttpRoute(
            name: "RpcStyleApi2",
            routeTemplate: "rest/{controller}/{id}/{action}",
            defaults: new { action = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "rest/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

Это, например, возвращает 404, потому что не может отличить «действие» от «идентификатора». «На контроллере «Клиент» не найдено действие, соответствующее имени «CID1234».

Чтобы получить необходимую мне гибкость, должен ли я использовать собственный селектор действий? Или это как-то возможно с помощью встроенных функций веб-API? Я понимаю, что кто-то может захотеть использовать заказы как отдельную сущность. Но с тем же успехом я мог бы иметь там настоящие «действия» (а не «сущности»). Например, «потерянный пароль», «изменить пароль» и так далее.

Спасибо за совет

PS: что-то вроде описанного здесь не совсем то, что я д быть готовым сделать. Плохой дизайн API.


person lapsus    schedule 06.02.2013    source источник
comment
Когда вы говорите, что ваши идентификаторы выглядят совсем по-другому? Что ты имеешь в виду? Они имеют префикс CID, как в вашем примере? - Марк Джонс только что отредактировал   -  person Mark Jones    schedule 06.02.2013
comment
Все они следуют шаблону. Но обычно каждая сущность имеет свой собственный отличительный паттерн. А иногда есть как старые, так и новые шаблоны, которые необходимо поддерживать. Например, существует 4 разных типа идентификаторов продуктов...   -  person lapsus    schedule 07.02.2013


Ответы (3)


На самом деле это одна из лучших практик при создании Restful API, вот небольшое видео о различных аспектах, которые следует учитывать при создании API https://www.youtube.com/watch?v=ZpqCN8iO9Y8

Решение. Вам не нужно менять маршрут сопоставления, все, что вам нужно, это использовать атрибуты метода поверх каждого метода, как показано ниже.

\\ api/clients [this should be clients not client if its returning a list]
[Route("api/clients")]
public IHttpActionResult Get()
{
   return Ok("here you list of clients");
}

/api/client/CID1234 (CID1234 = Id)
[Route("api/clients/{Id}")]
public IHttpActionResult Get(string Id)
{
   return Ok("use the Id to retrieve the client details");
}

/api/client/CID1234/orders (orders = action)
[Route("api/clients/{Id}/orders")]
public IHttpActionResult GetOrders(string Id)
{
   return Ok("use the Id to retrieve the client orders");
}

Насчет необязательного, теперь вы строите свою логику внутри метода по мере получения его значений.

В этой статье есть более подробная информация об этом пункте

https://aspnetwebstack.codeplex.com/wikipage?title=Attribute%20Routing%20in%20MVC%20and%20Web%20API

PS: используется .Net framework 4.5.2 с использованием owin

person Amgad Fahmi    schedule 30.03.2015

Если вы определяете свои маршруты следующим образом:

config.Routes.MapHttpRoute(
    name: "RpcStyleApi1",
    routeTemplate: "rest/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional, action = "Get" }
);

config.Routes.MapHttpRoute(
    name: "RpcStyleApi2",
    routeTemplate: "rest/{controller}/{id}/{action}"
);

Затем вы можете создавать методы на своем контроллере следующим образом:

public string Get()
{
    return "GET";
}

public string Get(string id)
{
    return "GETID";
}

public string Orders(string id)
{
    return "GETORDERS";
}

Это должно справиться с вашими комбинациями URL

  • /остальное/клиент
  • /остальное/клиент/CID1234
  • /остальное/клиент/CID1234/заказы
person Jon Susiak    schedule 27.03.2013

Не совсем уверен, почему ваш второй подход не работает, но приведенные ниже конфигурации маршрутизации работают для меня.

config.Routes.MapHttpRoute(
            name: "WebApiWithActionRouteName"
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "WebApiDefaultRouteName",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
person Sean Dong    schedule 20.09.2013