jueves, 3 de abril de 2014

ASP.NET MVC - Documentar Web Api

En un entorno servidor .NET un buen modo de plantear un proyecto Web Api es usando la plantilla de Visual Studio 2013.


En la plantilla, se crea un Area específica con una carpeta Help donde se ubican los controladores, views y clases necesarias para componer las páginas de documentación automáticamente a medida que vayamos añadiendo recursos a nuestra web api.

En caso de usar una versión de Visual Studio de 2012 es posible que tengamos que descargar ASP.NET and Web Tools 2012.2 Update para disponer de la página de ayuda por defecto.

Si tenemos que documentar una web api que no ha sido creada a partir de la plantilla podríamos descargarla de Nuget.
Install-Package Microsoft.AspNet.WebApi.HelpPage
En el ejemplo de hoy crearemos un servicio Artículo y jugaremos con su documentación. En primer lugar elimino el controlador de ejemplo que crea la plantilla (ValuesController).

En siguiente lugar me voy a la carpeta controllers de la root del proyecto y creo un controlador para artículo usando la plantilla de Controlador Web Api con acciones de lectura y escritura. Esto me genera una clase ArticuloController con las acciones CRUD sin implementar.

Veamos cómo queda la página de documentación:


Opino que como punto de partida para una documentación está bastante bien y si seguimos un patrón se irá documentando prácticamente sola a medida que se añadan nuevos recursos. A continuación expongo temas que me faltarían para tener una documentación útil e iré analizando punto a punto como podríamos hacerlo.

  • Personalizar la apariencia

  • Personalizar la descripción de cada uno de los métodos que se exponen para nuestros recursos y la descripción de la API en general

  • Dar una separación conceptual a la web api como los Namespace en una librería de clases. Por ejemplo en un entorno corporativo puede ser que aproveches la misma web api para servir recursos a diferentes áreas como financieras, recursos humanos, etc... Me interesaría que esta separación se reflejase de algún modo cuando accedes a la documentación.

A continuación os comento como se podría atacar cada uno de los 3 puntos que enumero.

Personalizar la Apariencia


La plantilla de ayuda nos ofrece 2 vistas, index.shtml que permite ver una lista de servicios y api.shtml que nos muestra el detalle de cada servicio.

Editando estos archivos podemos modificar el contenido html y podemos cambiar los estilos que se aplican a los elementos en la hoja de estilos HelpPage.css. De este modo podríamos personalizar el look & fill por defecto que nos ofrece la plantilla.

Personalizar la descripción de servicios y acciones


Hay varias opciones, la más sencilla sería pulsar botón derecho en el proyecto y en el apartado Compilar, se trata de activar esta casilla que se muestra en la imagen.


La descripción de los servicios y acciones la lee de los bloques “summary” que usamos para documentar nuestros controladores y acciones.
/// <summary>
/// Servicio ...
/// </summary>
public class ArticuloController : ApiController
// GET api/Articulo
/// <summary>
/// Obtiene una lista de …
/// </summary>
/// <returns>…</returns>
[HttpGet]
public IEnumerable<..> Get()
Si hacemos esto al volver a ejecutar el proyecto y cargar la página de nuevo debería mostrarnos esta información en las páginas de ayuda.

Tal vez pueda interesarnos también ocultar una acción (o recurso completo si usamos el atributo a nivel de controlador). Podríamos hacerlo del siguiente modo:
[ApiExplorerSettings(IgnoreApi=true)]
public HttpResponseMessage Get(int id) {  }

Separar la documentación en función de las áreas donde hemos ubicado los controladores de tipo ApiController


  • Generamos una lista con tantos elementos como diferentes áreas haya en el site MVC. Para ello en Global.asax una vez se ha llamado a AreaRegistration.RegisterAllRoutes() obtenemos todas las áreas que hay registradas en RouteTable y almacenamos el resultado en una variable de aplicación.
    this.Context.Application["areas"] = RouteTable.Routes.OfType<Route>().Where(d => d.DataTokens != null && d.DataTokens.ContainsKey("area")).Select(r => r.DataTokens["area"]).ToList();
    

  • Editamos el layout para generar tantos links en el menú superior como areas tenemos en el proyecto de manera dinámica:
    <ul class="nav navbar-nav">
       @{
          List<object> areas =     (List<object>)this.ViewContext.HttpContext.Application["areas"];   
       }
       @ foreach (string area in areas.Where(t => !t.ToString().Contains("HelpPage")))
       {
         <li>@Html.ActionLink(area, "Index/" + area, "Help")</li>
       }
    </ul>
    

  • Por último añadimos un parámetro ApiId a la acción Index del controlador HelpController y filtramos la lista de servicios que se muestran en función del valor que recibimos.
    public ActionResult Index(string apiId)
    {
      ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
    
      System.Collections.ObjectModel.Collection<System.Web.Http.Description.ApiDescription> servicios = new System.Collections.ObjectModel.Collection<System.Web.Http.Description.ApiDescription>();
      
    foreach (System.Web.Http.Description.ApiDescription description in Configuration.Services.GetApiExplorer().ApiDescriptions) 
    {
      if (description.ActionDescriptor.ControllerDescriptor.ControllerType.FullName.Contains("Areas." + apiId + "."))
        servicios.Add(description);
    }
    
    
      return View(servicios);
    }
    

Esta es la solución que he encontrado aunque no descarto que haya algún modo más elegante de hacerlo. Tener en cuenta que con esta solución que planteo no estamos autorizando por roles el acceso a la documentación, simplemente la estamos “separando” por áreas. Si queremos que sólo accedan a la documentación aquellos usuarios que están autorizados a hacer una petición a dichos servicios, podríamos llegar a hacerlo creándonos una acción por cada area en HelpController y desde el menú de Layout.shtml modificar los links que se están creando dinámicamente para que cada uno acceda a un controlador.

Tal vez también os pueda interesar crear un cliente de test aprovechando la misma plantilla de ayuda, os paso un link donde explica como hacerlo.

Hasta aquí el artículo de hoy, espero os sea de ayuda. Recordar que podéis participar en areaTIC si queréis o seguirnos a través de las principales redes sociales. Que vaya bien la semana!