📜 ⬆️ ⬇️

WebAPI: auto-generated REST API web documentation

In this blog entry, we take a closer look at ApiExplorer, which is the default IApiExplorer implementation, and see how it can be used to quickly generate web-based documentation on the available REST API. This documentation will contain a variety of information, such as valid URLs, valid HTTP methods, parameters expected for requests. This kind of information for your REST service will allow third-party developers consuming your API to know exactly how to properly call its parts. Probably the best part of such a web documentation page is that it will be updated automatically along with the update of your REST API.

ApiExplorer


The main goal of this class is to generate a collection of ApiDescription elements. This is done using static route checking and available actions inside your controllers. Each ApiDescription element describes an API accessible through your service. As you can see in the simplified diagram (Figure 1), the ApiDescription contains basic information such as, HttpMethod, RelativePath, Documentation, etc. But in addition, it contains the ApiDescriptor element, which is part of the WebAPI core that knows all about the corresponding action. You can use this element to access extensive information, such as the name of the action, the return type, custom attributes, etc. Similarly, you can use the ParameterDescriptor element to examine the expected parameters of this API.

clip_image001
Fig.1. ApiDescription class diagram

Let's see how we can generate a help page.
')

API help page generation


For simplicity, I will assume that we use our REST service along with ASP.NET MVC. You can find other implementation ideas below in the Other Implementation section.

Example


For example, I use the standard "Web API" template.

clip_image002
Fig.2. Choosing a Web API project

By default, this template contains the HomeController MVC controller and ValuesController Web API. Let's change the Index action in HomeController in order to display our help page.

Step 1. Use ApiExplorer in the view.


Add the following two lines of code to the Index action:

public ActionResult Index() { var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer(); return View(apiExplorer); } 

Step 2. Configure the view to display the API


In Index.cshtml we can specify the type of the IApiExplorer model:

@model System.Web.Http.Description.IApiExplorer

Then we can go through all the elements of Model.ApiDescriptions to display the supported HTTP methods, relative URLs, description of actions and expected parameters.

 @foreach (var api in Model.ApiDescriptions) { <li> <h5>@api.HttpMethod @api.RelativePath</h5> <blockquote> <p>@api.Documentation</p> @if (api.ParameterDescriptions.Count > 0) { <h6>Parameters</h6> <ul> @foreach (var parameter in api.ParameterDescriptions) { <li>@parameter.Name: @parameter.Documentation (@parameter.Source)</li> } </ul> } </blockquote> </li> } 

Of course, you can customize your HTML markup as you like. Below is the complete code for the presentation:

 @model System.Web.Http.Description.IApiExplorer <div id="body"> <section class="featured"> <div class="content-wrapper"> <hgroup class="title"> <h1>ASP.NET Web API Help Page</h1> </hgroup> </div> </section> <section class="content-wrapper main-content clear-fix"> <h3>APIs</h3> <ul> @foreach (var api in Model.ApiDescriptions) { <li> <h5>@api.HttpMethod @api.RelativePath</h5> <blockquote> <p>@api.Documentation</p> @if (api.ParameterDescriptions.Count > 0) { <h6>Parameters</h6> <ul> @foreach (var parameter in api.ParameterDescriptions) { <li>@parameter.Name: @parameter.Documentation (@parameter.Source)</li> } </ul> } </blockquote> </li> } </ul> </section> </div> 

Now, after launching the application, you should see the following page describing the available REST API (Figure 3).

clip_image003
Fig.3. Web Documentation Page

If you take a closer look, the API description just says "Documentation for XYZ", which of course is not very useful. Let's add some useful information.

Step 3. Adding Documentation


During the generation of documentation for the API, our ApiExplorer requests an IDocumentationProvider to provide the necessary information. IDocumentationProvider is an abstract mechanism that allows you to define your own way of obtaining information for documenting API actions. This allows you to implement your own IDocumentationProvider, which will extract information from the source you need. Below you can find an example implementation of IDocumentationProvider, which extracts information from C # documenting comments.

 public class XmlCommentDocumentationProvider : IDocumentationProvider { XPathNavigator _documentNavigator; private const string _methodExpression = "/doc/members/member[@name='M:{0}']"; private static Regex nullableTypeNameRegex = new Regex(@"(.*\.Nullable)" + Regex.Escape("`1[[") + "([^,]*),.*"); public XmlCommentDocumentationProvider(string documentPath) { XPathDocument xpath = new XPathDocument(documentPath); _documentNavigator = xpath.CreateNavigator(); } public virtual string GetDocumentation(HttpParameterDescriptor parameterDescriptor) { ReflectedHttpParameterDescriptor reflectedParameterDescriptor = parameterDescriptor as ReflectedHttpParameterDescriptor; if (reflectedParameterDescriptor != null) { XPathNavigator memberNode = GetMemberNode(reflectedParameterDescriptor.ActionDescriptor); if (memberNode != null) { string parameterName = reflectedParameterDescriptor.ParameterInfo.Name; XPathNavigator parameterNode = memberNode.SelectSingleNode(string.Format("param[@name='{0}']", parameterName)); if (parameterNode != null) { return parameterNode.Value.Trim(); } } } return "No Documentation Found."; } public virtual string GetDocumentation(HttpActionDescriptor actionDescriptor) { XPathNavigator memberNode = GetMemberNode(actionDescriptor); if (memberNode != null) { XPathNavigator summaryNode = memberNode.SelectSingleNode("summary"); if (summaryNode != null) { return summaryNode.Value.Trim(); } } return "No Documentation Found."; } private XPathNavigator GetMemberNode(HttpActionDescriptor actionDescriptor) { ReflectedHttpActionDescriptor reflectedActionDescriptor = actionDescriptor as ReflectedHttpActionDescriptor; if (reflectedActionDescriptor != null) { string selectExpression = string.Format(_methodExpression, GetMemberName(reflectedActionDescriptor.MethodInfo)); XPathNavigator node = _documentNavigator.SelectSingleNode(selectExpression); if (node != null) { return node; } } return null; } private static string GetMemberName(MethodInfo method) { string name = string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name); var parameters = method.GetParameters(); if (parameters.Length != 0) { string[] parameterTypeNames = parameters.Select(param => ProcessTypeName(param.ParameterType.FullName)).ToArray(); name += string.Format("({0})", string.Join(",", parameterTypeNames)); } return name; } private static string ProcessTypeName(string typeName) { //handle nullable var result = nullableTypeNameRegex.Match(typeName); if (result.Success) { return string.Format("{0}{{{1}}}", result.Groups[1].Value, result.Groups[2].Value); } return typeName; } } 

After that you need to connect your own IDocumentationProvider. The easiest way to do this is to configure it via HttpConfiguration. Note that the XmlCommentDocumentationProvider needs to know where the XML file is with comments.

 var config = GlobalConfiguration.Configuration; config.Services.Replace(typeof(IDocumentationProvider), new XmlCommentDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/MyApp.xml"))); 

You can make sure that the generation of your XML documentation file is enabled in the project settings (Figure 4).

clip_image004
Fig.4. Setting the file generation parameter of the documentation

After that, make sure that your code contains documentation comments:

clip_image005

Finally, run your project again and make sure that the documentation from your code is now available on the web documentation page of your REST API (Figure 5).

clip_image006
Fig.5. Web documentation page with description of methods

Exclude controller / action from documentation


For some reason, it may be necessary to exclude a controller or action from the generation of API documentation. To do this, you can use the special attribute ApiExplorerSettingsAttribute:

 public class ValuesController : ApiController { [ApiExplorerSettings(IgnoreApi = true)] public void MySpecialAction() { } } 

It can also be used for the controller:

 [ApiExplorerSettings(IgnoreApi = true)] public class MySpecialController : ApiController { 

Other implementations


What I showed above is just one way to implement the web documentation page. But there may be many other ways, for example, another idea:

Translator's Note


The article describes the future functionality that will be added to ASP.NET WebAPI. You can try it today by installing the necessary packages from the WebAPI repository aspnetwebstack.codeplex.com/.../353867 for details on how this can be done is written in a separate article .

Source: https://habr.com/ru/post/144915/


All Articles