Swagger: Trying to clean the xml documentation before giving it to swashbuckle

This commit is contained in:
Zoe Roux 2021-09-20 12:44:29 +02:00
parent ced12c2fe6
commit e32dcd0f30
4 changed files with 123 additions and 3 deletions

View File

@ -31,14 +31,28 @@ using static Kyoo.Abstractions.Models.Utils.Constants;
namespace Kyoo.Core.Api namespace Kyoo.Core.Api
{ {
/// <summary>
/// Information about one or multiple <see cref="Collection"/>.
/// </summary>
[Route("api/collections")] [Route("api/collections")]
[Route("api/collection", Order = AlternativeRoute)] [Route("api/collection", Order = AlternativeRoute)]
[ApiController] [ApiController]
[PartialPermission(nameof(CollectionApi))] [PartialPermission(nameof(CollectionApi))]
public class CollectionApi : CrudApi<Collection> public class CollectionApi : CrudApi<Collection>
{ {
/// <summary>
/// The library manager used to modify or retrieve information about the data store.
/// </summary>
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
/// <summary>
/// The file manager used to send images.
/// </summary>
private readonly IFileSystem _files; private readonly IFileSystem _files;
/// <summary>
/// The thumbnail manager used to retrieve images paths.
/// </summary>
private readonly IThumbnailsManager _thumbs; private readonly IThumbnailsManager _thumbs;
public CollectionApi(ILibraryManager libraryManager, public CollectionApi(ILibraryManager libraryManager,
@ -52,6 +66,20 @@ namespace Kyoo.Core.Api
_thumbs = thumbs; _thumbs = thumbs;
} }
/// <summary>
/// Lists <see cref="Show"/> that are contained in the <see cref="Collection"/> with id <paramref name="id"/>.
/// </summary>
/// <param name="id">The ID of the <see cref="Collection"/>.</param>
/// <param name="sortBy">A key to sort shows by. See <see cref="Sort{T}"/> for more information.</param>
/// <param name="afterID">An optional show's ID to start the query from this specific item.</param>
/// <param name="where">
/// An optional list of filters. See <see cref="ApiHelper.ParseWhere{T}"/> for more details.
/// </param>
/// <param name="limit">The number of shows to return.</param>
/// <returns>A page of shows.</returns>
/// <response code="200">A page of shows.</response>
/// <response code="400"><paramref name="sortBy"/> or <paramref name="where"/> is invalid.</response>
/// <response code="404">No collection with the ID <paramref name="id"/> could be found.</response>
[HttpGet("{id:int}/shows")] [HttpGet("{id:int}/shows")]
[HttpGet("{id:int}/show", Order = AlternativeRoute)] [HttpGet("{id:int}/show", Order = AlternativeRoute)]
[PartialPermission(Kind.Read)] [PartialPermission(Kind.Read)]

View File

@ -28,21 +28,47 @@ using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Core.Api namespace Kyoo.Core.Api
{ {
/// <summary>
/// A base class to handle CRUD operations on a specific resource type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of resource to make CRUD apis for.</typeparam>
[ApiController] [ApiController]
[ResourceView] [ResourceView]
public class CrudApi<T> : ControllerBase public class CrudApi<T> : ControllerBase
where T : class, IResource where T : class, IResource
{ {
/// <summary>
/// The repository of the resource, used to retrieve, save and do operations on the baking store.
/// </summary>
private readonly IRepository<T> _repository; private readonly IRepository<T> _repository;
/// <summary>
/// The base URL of Kyoo. This will be used to create links for images and <see cref="Abstractions.Models.Page{T}"/>.
/// </summary>
protected Uri BaseURL { get; } protected Uri BaseURL { get; }
/// <summary>
/// Create a new <see cref="CrudApi{T}"/> using the given repository and base url.
/// </summary>
/// <param name="repository">
/// The repository to use as a baking store for the type <typeparamref name="T"/>.
/// </param>
/// <param name="baseURL">
/// The base URL of Kyoo to use to create links.
/// </param>
public CrudApi(IRepository<T> repository, Uri baseURL) public CrudApi(IRepository<T> repository, Uri baseURL)
{ {
_repository = repository; _repository = repository;
BaseURL = baseURL; BaseURL = baseURL;
} }
/// <summary>
/// Get a <typeparamref name="T"/> by ID.
/// </summary>
/// <param name="id">The ID of the resource to retrieve.</param>
/// <returns>The retrieved <typeparamref name="T"/>.</returns>
/// <response code="200">The <typeparamref name="T"/> exist and is returned.</response>
/// <response code="404">A resource with the ID <paramref name="id"/> does not exist.</response>
[HttpGet("{id:int}")] [HttpGet("{id:int}")]
[PartialPermission(Kind.Read)] [PartialPermission(Kind.Read)]
public virtual async Task<ActionResult<T>> Get(int id) public virtual async Task<ActionResult<T>> Get(int id)

View File

@ -66,9 +66,7 @@ namespace Kyoo.Swagger
} }
}); });
foreach (string documentation in Directory.GetFiles(AppContext.BaseDirectory, "*.xml")) options.LoadXmlDocumentation();
options.IncludeXmlComments(documentation);
options.UseAllOfForInheritance(); options.UseAllOfForInheritance();
options.SwaggerGeneratorOptions.SortKeySelector = x => x.RelativePath; options.SwaggerGeneratorOptions.SortKeySelector = x => x.RelativePath;
options.DocInclusionPredicate((_, apiDescription) options.DocInclusionPredicate((_, apiDescription)

View File

@ -0,0 +1,68 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Kyoo.Swagger
{
/// <summary>
/// A static class containing a custom way to include XML to Swagger.
/// </summary>
public static class XmlDocumentationLoader
{
/// <summary>
/// Inject human-friendly descriptions for Operations, Parameters and Schemas based on XML Comment files
/// </summary>
/// <param name="options">The swagger generator to add documentation to.</param>
public static void LoadXmlDocumentation(this SwaggerGenOptions options)
{
ICollection<XDocument> docs = Directory.GetFiles(AppContext.BaseDirectory, "*.xml")
.Select(XDocument.Load)
.ToList();
Dictionary<string, XElement> elements = docs
.SelectMany(x => x.XPathSelectElements("/doc/members/member[@name and not(inheritdoc)]"))
.ToDictionary(x => x.Attribute("name")!.Value, x => x);
foreach (XElement doc in docs
.SelectMany(x => x.XPathSelectElements("/doc/members/member[inheritdoc[@cref]]")))
{
if (elements.TryGetValue(doc.Attribute("cref")!.Value, out XElement member))
doc.Element("inheritdoc")!.ReplaceWith(member);
}
foreach (XElement doc in docs.SelectMany(x => x.XPathSelectElements("//see[@cref]")))
{
string fullName = doc.Attribute("cref")!.Value;
string shortName = fullName[(fullName.LastIndexOf('.') + 1)..];
// TODO won't work with fully qualified methods.
if (fullName.StartsWith("M:"))
shortName += "()";
doc.ReplaceWith(shortName);
}
foreach (XDocument doc in docs)
options.IncludeXmlComments(() => new XPathDocument(doc.CreateReader()), true);
}
}
}