• Eduard Stefanescu

Documentarea codului în ASP.NET Core folosind Swagger



Acest articol va fi despre crearea documentației unei aplicații web API în ASP.NET Core folosind Swagger. Prima parte va conține o scurtă introducere, iar în a doua parte, implementarea acestui instrument va fi explicată.


Necesitatea documentării codului

Documentarea codului (în eng.: documentation) este unul dintre cele mai bune moduri de a transfera cunoștințele unui întreg proiect sau doar a unei anumite părți din acesta. Documentația poate fi folosită ca un instrument de învățare pentru un nou membru al echipei și poate fi folosită ca punct de referință atunci când cineva vrea să verifice dacă presupunerile sunt corecte. Dar principalul avantaj pentru a scrie sau a folosi un instrument care generează documentație înainte sau în timpul dezvoltării este acela că poate scoate la suprafață unele probleme sau idei la care nimeni nu s-ar fi gândit.


Introducere

Swagger face parte din inițiativa OpenAPI, principalul avantaj fiind acela ca poate fi folosit de mai multe limbaje de programare, cum ar fi Java Spring, Python și multe altele. Această inițiativă oferă multe instrumente, unul dintre acesta este Swagger Hub care poate fi folosit pentru a crea documentația unei aplicații web de tipul API, fără a folosi un limbaj de programare pentru a-l descrie; sau Swagger Inspector este un instrument pentru a testa API-ul.

În .NET, mediul Swagger Specification se folosește de fișierele generate de către acesta, dar mai jos în acest articol va fi explicat cum se poate activa generarea acestor fișiere. Acest mediu include și o componenta grafică, care ilustrează rutele Web API-ului, acesta incluzând:

  • metodele de request HTTP (de exemplu GET sau POST);

  • parametrii și parametrii de interogare;

  • codurile de răspuns (de exemplu OK sau NotFound);

  • o descriere a fiecărei rute, parametrii și ce tip de obiect returnează;


Cerințe prealabile

Pentru acest articol, a fost generat un proiect ASP.NET Core, așadar Controller-ul WeatherForecast va fi folosit pentru a descrie API-ul. Așa cum a fost menționat anterior, Framework-ul Swagger va avea nevoie de un fișier pentru a crea documentația. Astfel, pentru a genera acest fișier, trebuie setată proprietatea GenerateDocumentionFile cu valoarea true în fișierul proiectului ASP.NET Core, asemănător ca în Imaginea 1.

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

Imaginea 1. Activarea proprietății GenerateDocumentationFile.


Prin activarea acestei proprietăți în fișierul de configurare al proiectului (adică în csproj), în momentul compilări proiectului, compilatorul va căuta comentariile de tip XML și va genera un fișier XML conținând toate comentariile găsite [1], ca în Imaginea 2 de mai jos.

<doc>
 <assembly>
 <name>API.WithoutAuthentication</name>
 </assembly>
 <members>
 <member name="T:API.WithoutAuthentication.Controllers.WeatherForecastController">
 <summary>
          List the weather forecasts.
 </summary>
 </member>
 </members>
</doc>

Imaginea 2. Secțiune din fișierul XML generat.

Nu ar trebuie sa ne preocupe cum arată acest fișier XML sau secvența de cod de mai sus, deoarece are scop informativ. Așadar în partea de sus, se găsește numele assembly-ului, reprezentând faptul că dacă sunt mai multe proiecte, atunci se va genera câte un fișier XML asemănător cu cel de mai sus, dar doar dacă proprietatea GenerateDocumentionFile a fost activată. Sub aceasta parte, sunt enumarați toți membrii cărora li s-au găsit comentarii de tip XML. În acest caz, este descris constructorul clasei WeatherForecastController, conținând un scurt rezumat. Dar dacă descrierea ar fi fost mai mare, conținând mai mulți specificatori, precum params sau response, atunci aceștia ar fi fost de asemenea incluși.

După activarea acestei proprietăți și recompilarea proiectului, vor fi afișate câteva avertismente, care descriu că unele tipuri sau membrii ale claselor nu sunt descriși, precum în Imaginea 3 de mai jos.

Imaginea 3. Avertismentele afișate în lista de erori după compilarea proiectului cu proprietatea GenerateDocumentationFile.


Aceste avertismentele provin și din clase care nu ar trebui să fie incluse în documentația API-ului, cum ar fi clasele Startup sau Program. Dar acestea se pot dezactiva, folosind directiva preprocesorului pragma, așa cum este descris mai jos în Imaginea 4.

#pragma warning disable 1591

Imaginea 4. Preprocesorul pragma pentru dezactivarea avertismentelor din clasele care nu au nevoie de documentație.


Directiva pragma primește câțiva parametrii, primul este numele pragma, în acest caz se vor dezactiva doar avertismentele, apoi argumentele disable și 1591 [2]. Ultimul argument este numărul de avertizare, care poate fi găsit în lista de erori. După ce argumentele inutile au fost dezactivate, în lista de erori vor fi văzute doar cele care trebuie luate în considerare și pentru care se vor scrie comentarii XML, precum în Imaginea 3.

După generarea fișierului XML și ștergerea avertismentelor nenecesare, trebuie instalate următoarele două pachete pentru a genera documentația cu Swagger și pentru a o vizualiza într-un mod cât mai lizibil, folosind o pagină Web.


Scrierea comentariilor XML

Comentariile XML trebuie să fie clare și să ofere suficiente informații pentru ca utilizatorii API-ului să îl înțeleagă fără a avea îndoieli. Este posibil să existe unele concepții greșite despre scrierea comentariilor, dar în acest caz, scrierea acestor comentarii îi va ajuta pe alții să înțeleagă ce informații trebuie să trimită folosind anumite rute, deoarece în majoritatea cazurilor nu vor avea acces la codul sursă. În lista de mai jos, sunt câteva exemple de API-uri publice.


Descrierea parametrilor

În Imaginea 5, este reprezentat un scurt rezumat al constructorului clasei WeatherForecastController, fiind descris și parametrul logger.

// <summary>
/// Constructs the controller state.
/// </summary>
/// <param name="logger">Injected logger by the dependency injection container.</param>
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
   this.logger = logger;
}

Imaginea 5. Utilizarea etichetei param.


Secțiunea de cod din Imaginea 5, ilustrează modul în care poate fi setată eticheta param, dacă există mai mulți parametrii, atunci trebuie adăugată câte o etichetă pentru fiecare parametru [3].

Iar în Imaginea 6, sunt folosite etichetele returns și response pentru endpoint-ul /GET. Acestea ar trebuie sa fie etichetele de bază ale oricărei rute a API-ului, astfel încât să fie descrise într-un mod inteligibil.


/// <summary>
/// Get the weather forecast 
/// </summary>
/// <returns>Returns a list of five weather forecast elements, with random temperatures
/// between -20 and 55 degrees.</returns>
/// <response code="200">Returns the list of weather forecast elements.</response>
/// <response code="500">If an exception is thrown.</response>
[HttpGet]
public IActionResult Get()
{
    ...
} 

Imaginea 6. Utilizarea etichetelor return și response.


Adăugarea generatorului pentru serviciul Swagger

În clasa Startup, trebuie să se adauge generatorul serviciului Swagger, pentru a genera fișierul swagger.json, care va fi ulterior analizat de o componentă middleware astfel încât documentația să fie afișată într-o pagină Web. Pentru acest pas, s-a creat un extension method pentru a menține codul organizat. Dar tot codul din această metodă, ilustrat în Imaginea 7, ar fi putut fi adăugat direct în clasa Startup din metoda ConfigureServices.

public static IServiceCollection AddSwaggerDocumentation(this IServiceCollection services)
{
    services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc(name: "acme",
            new OpenApiInfo { Title = "Acme API", Version = "v1" });

        string xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
        string xmlFilePath = Path.Combine(AppContext.BaseDirectory, xmlFile);

        options.IncludeXmlComments(xmlFilePath);
    });

    return services;
}

Imaginea 7. Configurația generatorului pentru serviciul Swagger.


În codul de mai sus au fost configurate opțiunile minime necesare pentru a genera documentația Swagger. Pe linia 5 este configurată Documentația API, cu numele, titlul și versiunea. Apoi calea de fișier XML a assembly-ului curent este construită și trimisă metodei IncludeXmlComments ca referință, aceasta va fi folosită înainte de generarea fișierul swagger.json. Toate proprietățile disponibile ale generatorului pot fi găsite pe pagina Swashbuckle.AspNetCore GitHub https://git.io/JftOr.


Adăugarea middleware-ului Swagger

Asemănător cu metoda de extensie a generatorului pentru serviciu Swagger, există de asemenea o astfel de metodă pentru a adăuga două middlewares, una pentru Swagger Documentation și alta pentru SwaggerUI, după cum se poate observa în Imaginea 8. Aceste două middlewares pot fi adăugate și direct în metoda Configure din clasa Startup.

public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app)
{
    app.UseSwagger();
    app.UseSwaggerUI(options =>
    {
 options.SwaggerEndpoint("/swagger/acme/swagger.json", "Acme API v1");
 options.DocExpansion(DocExpansion.None);
    });

 return app;
}

Imaginea 8. Metoda de extensie pentru adaugarea Swagger Documentation și SwaggerUI.


Pe linia 3 este adăugat middleware-ul Swagger Documentation, care va genera swagger.json. Apoi SwaggerUI este adăugat și configurat, specificând calea către fișierul swagger.json și numele care va fi afișat în partea de sus a paginii. După cum puteți observa numele Documentației API, care a fost setat anterior în generatorul pentru serviciul Swagger, în acest caz, numele fiind acme, va fi folosit și în ruta endpoint-ului Swagger. Dacă numele va fi diferit, pagina web Swagger va afișa următoarea eroare, ca în Imaginea 9.


Imaginea 9. Mesajul de eroare afișat când fișierul swagger.json nu există deoarece nu a fost configurat corect.


Iar pe linia 7, opțiunea Expansion este setată pe None, care va colapsa toate definițiile API-ului atunci când se deschide pagina web Swagger. Aceasta este mai mult o preferință personală, deoarece pe măsură ce aplicația crește, vor exista zeci sau sute de definiții ale rutelor.


Rezultatul

După efectuarea tuturor etapelor de mai sus, acum pagina web cu documentația API-ului poate fi deschisă accesând http://localhost:5000/swagger/index.html. În Imaginea 10 de mai jos este afișată pagina de destinație cu panoul WeatherForecast deschis.

Imaginea 10. Panoul cu ruta /GET WeatherForecast.


Prin folosirea butonului Try it out poate fi testat endpoint-ul, asemenător cu testarea acestuia folosind Postman, Insomnia sau orice alt client REST, dar mult mai ușor, fără a fi nevoie să se introducă nimic. În următorul articol se va adăuga autentificarea Bearer, unde autentificarea se va face o singură dată.

Imaginea 11. Testarea endpoint-ului utilizând butonul Try it out.


Codul sursă din acest articol poate fi găsit pe contul meu GitHub: https://github.com/StefanescuEduard/DotnetSwaggerDocumentation/tree/master/API.WithoutAuthentcation.


Îți mulțumim că ai citit acest articol, dacă ți se pare interesant, te rugăm să-l distribui colegilor și prietenilor. Sau dacă găsești ceva care poate fi îmbunătățit, te rugăm să ne spui.


Bibliografie

[1] https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc

[2] https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-pragma

[3] https://docs.microsoft.com/en-us/dotnet/csharp/codedoc