revelio

Enterprise Web API Documentation

Custom views

Revelio supports additional information to be added to API endpoints in the form of metadata. This structured data can be used to supplement Revelio's standard functionality. For example, you may wish to keep track of the date an endpoint was added, stored as a simple date string. This information will automatically show on the Revelio page.

With this minimal information, the default view might be acceptable. But what if we want more information about the author? Perhaps their name, email address, and the story number this endpoint was created for.

Default metadata view

The default view for structured data might be good enough, but what if we want to make the email address a mailto link? Also, the date should have a common format, and QA has asked for the story number to link to the actual story. Revelio supports fully customizing these views.

Structured data is formatted as YAML

Creating a custom view

The first step is to create a new file named Metadata_Endpoint_[metadata_key].cshtml. For example, a custom view for the metadata above would be Metadata_Endpoint_Creation_Info.cshtml (note that spaces are replaced by underscores). This file uses Razor syntax. Then, open up the file in an editor and paste the following at the top:

@using Revelio.Helpers
@{ var viewModel = this.GetMetadataViewModel<dynamic>(); }

This gets the view model from which we can retrieve our metadata. Below this, we'll add the code to display the creation information.

<div>Created @DateTime.Parse(viewModel.Date.ToString()).ToString("MMMM d, yyy")</div>
<div>Author: <a href="mailto:@viewModel.Email">@viewModel.Name</a></div>
<div>Story: <a href="http://www.tempuri.org/story/@viewModel.Number" target="_blank">@viewModel.Number</a></div>

And that's it! This file needs to be placed in the [Revelio_installation]/Views/Shared folder. Then once we reload the screen, we'll see our changes.

You can repeat these steps with any other metadata you need to display.

Custom view for creation information

Taking it further

If you're dealing with more complex types in your metadata, you may wish to revise the approach above to use a strongly-typed approach. Fortunately, you can take advantage of the @functions feature of Razor.

We may also want to account for the author providing partial information. In the view above, if they didn't provide a Date, we would get a null reference exception.

The code below shows how we would accomplish both these changes:

@using Revelio.Helpers
@functions {
    public class CreationInfoViewModel
    {
        public DateTime? Date { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Number { get; set; }
    }
}
@{ var viewModel = this.GetMetadataViewModel<CreationInfoViewModel>(); }

@if (viewModel.Date.HasValue)
{
    <div>Created @viewModel.Date.Value.ToString("MMMM d, yyy")</div>
}
@if (!String.IsNullOrEmpty(viewModel.Email))
{
    <div>Author: <a href="mailto:@(viewModel.Email)">@viewModel.Name</a></div>
}
@if (!String.IsNullOrEmpty(viewModel.Number))
{
    <div>Story: <a href="http://www.tempuri.org/story/@viewModel.Number" target="_blank">@viewModel.Number</a></div>
}

Reference

The following is the code used to generate the Creation Info metadata. See the Extending Revelio page for more information.

public class DateAddedAttribute : CreationInfoBase, IEndpointDocumentationAttribute
{
    private readonly string _date;

    public DateAddedAttribute(string date)
    {
        _date = date;
    }

    public void AddInfo(ApiEndpointInfo endpoint)
    {
        var info = GetInfo(endpoint);
        info.Date = _date;
    }
}
public class AuthorInfoAttribute : CreationInfoBaseAttribute, IEndpointDocumentationAttribute
{
    private readonly string _name;
    private readonly string _emailAddress;

    public AuthorInfoAttribute(string name, string emailAddress)
    {
        _name = name;
        _emailAddress = emailAddress;
    }

    public void AddInfo(ApiEndpointInfo endpoint)
    {
        var info = GetInfo(endpoint);
        info.Name = _name;
        info.Email = _emailAddress;
    }
}
public class StoryNumberAttribute : CreationInfoBaseAttribute, IEndpointDocumentationAttribute
{
    private readonly string _number;

    public StoryNumberAttribute(string number)
    {
        _number = number;
    }

    public void AddInfo(ApiEndpointInfo endpoint)
    {
        var info = GetInfo(endpoint);
        info.Number = _number;
    }
}
public class CreationInfoBaseAttribute : Attribute
{
    private const string CreationInfoKey = "Creation Info";

    protected CreationInfo GetInfo(ApiEndpointInfo endpoint)
    {
        var creationInfo = endpoint.GetMetadata<CreationInfo>(CreationInfoKey);

        if (creationInfo == null)
        {
            creationInfo = new CreationInfo();
            endpoint.AddMetadata(CreationInfoKey, creationInfo);
        }

        return creationInfo;
    }
}

public class CreationInfo
{
    public string Date { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Number { get; set; }
}