Skip to content

Instantly share code, notes, and snippets.

@DoggettCK
Created October 1, 2014 20:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DoggettCK/e6da2981096968b43e15 to your computer and use it in GitHub Desktop.
Save DoggettCK/e6da2981096968b43e15 to your computer and use it in GitHub Desktop.
API self-documentation
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Hosting;
using System.Web.Http;
using System.Web.Http.Description;
using NLog;
namespace Project.Controllers.API {
///
/// Controller for providing discoverable API
///
[ApiExplorerSettings(IgnoreApi = true)]
[Authorize]
public class DiscoveryController : ApiController {
private readonly Logger _logger;
///
/// Default constructor
///
public DiscoveryController() {
_logger = LogManager.GetCurrentClassLogger();
}
///
/// Lists all publicly-available API calls
///
/// JSON list of API methods, relative paths, and parameters
[AcceptVerbs("GET"), ActionName("get")]
public HttpResponseMessage DiscoverAPI() {
_logger.Info(string.Format("Request: {0}", Request.RequestUri));
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Services.Replace(typeof (IDocumentationProvider), new ApiDocumentationProvider(HostingEnvironment.MapPath("~/App_Data/Documentation.xml")));
IApiExplorer apiExplorer = config.Services.GetApiExplorer();
var apiDescriptions = apiExplorer.ApiDescriptions.Select(
delegate(ApiDescription api) {
var parts = api.RelativePath.Split(new[] {"?"}, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 0) {
parts[0] = parts[0].ToLowerInvariant();
}
var cleanedPath = String.Join("?", parts);
return new
{
RelativePath = cleanedPath,
api.HttpMethod.Method,
SupportedResponseFormats = api.SupportedResponseFormatters.SelectMany(formatter => formatter.SupportedMediaTypes.Select(format => format.MediaType)),
SupportedEncodings = api.SupportedResponseFormatters.SelectMany(formatter => formatter.SupportedEncodings.Select(encoding => encoding.HeaderName)),
api.Documentation,
Parameters = api.ParameterDescriptions.Select(
param => new
{
param.Name,
Source = ParameterSourceToString(param.Source),
param.Documentation,
Descriptor = new
{
Default = param.ParameterDescriptor.DefaultValue,
Optional = param.ParameterDescriptor.IsOptional,
Type = TypeNameToProviderAgnosticName(param.ParameterDescriptor.ParameterType.Name),
}
})
};
});
return Request.CreateResponse(HttpStatusCode.OK, new {Items = apiDescriptions});
}
private String ParameterSourceToString(ApiParameterSource source) {
switch (source) {
case ApiParameterSource.FromUri:
return "From URL";
case ApiParameterSource.FromBody:
return "From Body";
default:
return "Unknown";
}
}
private String TypeNameToProviderAgnosticName(string typeName) {
if (String.IsNullOrWhiteSpace(typeName)) return null;
switch (typeName.ToLowerInvariant()) {
case "string":
return "String";
case "uint32":
return "Unsigned 32-bit integer";
case "int32":
return "Signed 32-bit integer";
case "uint64":
return "Unsigned 64-bit integer";
case "int64":
return "Signed 64-bit integer";
case "boolean":
return "Boolean";
default:
return typeName;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment