Last Updated on November 18, 2022 by Aram
Swagger can help you document your APIs by representing your API definition in a JSON format, which is called the OpenAPI Specification document, OpenAPI was originally part of Swagger project and later on got split into separate project where it got backed up by the open source community.
OpenAPI specification represent a set of guidelines and structure of how an API can be represented and documented in a standard format to ease the processed of integration with this API.
In this tutorial we will see how Swagger is implemented in ASP.NET Core Web API, and how can we configure it to support different features and customizations on the APIs, like adding description, request/response types, custom headers, and most importantly security headers like authorization.
Also we will learn how to use the Swagger UI to test and verify our APIs directly from the browser.
In order to show you how to implement the correct configurations for the different requests for Swagger as mentioned above, we will be using one of my GitHub projects that has a full implementation for JWT Authentication, so that we can showcase how can we implement and test swagger with the authorization header, and we will be adding more features under this project to see the Swagger configurations for predefined header as well as file upload with content-type as multipart/form-data.
This tutorial will be based on .NET 7, the latest and greatest version of .NET, which has been recently announced throughout the the 3-days long great conference of .NET (DotNet Conf 2022), you can still use .NET 6 as it will remain under LTS for until November 2024.
To start using .NET 7, you can either download the SDK from here , or update your Visual Studio 2022 to the latest version now which is 17.4.0 , this has the .NET 7 bundled in it. Check here for the release notes.
Bundled with the latest version of .NET, you will get the latest version of SwashBuckle Nuget, which includes the needed classes and methods to build and generate the latest version of Swagger or OpenAPI Specification documentation for your ASP.NET Core Web API project.
Just for the information, the latest version of OpenAPI Specification is 3.1.0, and fortunately building with ASP.NET Core Web API 6 or 7 produces the Swagger documentation for your Web APIs according to the latest OpenAPI Specification major version 3.
So let’s start this tutorial to see how can we implement Swagger in ASP.NET Core Web API
Let’s start by opening Visual Studio 2022 and choose clone a repository, and specify this below link:
https://github.com/aram87/TasksApi
Then choose Clone.
You should be getting the below solution structure, then you can rebuild the solution to make sure all packages are installed and you are ready to go:
Press F5 to run the project and wait until you see the Swagger UI showing a nicely designed page with all your endpoints categories under each of your Controller name:
And then if you expand any of the endpoints, you can see the different details of the endpoint like input or request parameters (if any), as well you can test the request and see the results appear directly on the page, so let’s try to test the GET Tasks endpoint, and see what we will get.
Press on the button ‘Try it Out’ and then on ‘Execute’:
As you can see from the above screen, we got http status code 401, which means unauthorized, simply because this endpoint expects an authorization header with a valid Bearer JWT Token.
But if you notice, on this Swagger UI page, we don’t have clear explanation for this endpoint, for the response or anything to help us know what should we provide for this endpoint. This is because Swagger doesn’t know, by default, all these details.
Also there is no way that we can provide any sort of Authorization header for any of the protected APIs.
This means that we have to provide it all these information through different attributes and configurations.
Now, since we are using .NET 6, and I haven’t previously done anything specific on the project to add Swagger, since it came already bundled with Swashbuckle Nuget package and configured in the Program.cs file.
In fact, If you open Program.cs file, you will see the initial setup for Swagger, as the below:
AddEndpointsApiExplorer is used for minimal APIs, but it is always there for no specific reason. You can read this SO thread for more details. So you don’t need to worry about it for now, at least because we are not using minimal APIs here in this project or tutorial.
What we care about it the AddSwaggerGen()
, this is an extension method inside the Swashbuckle nuget, that wraps the configurations and bindings of all the Swagger related generators as well as enabling the ApiExplorer, which eventually ends up in generating the OpenAPI specification v3 documentation for your endpoints (as defined by your controllers).
Swagger OpenAPI Specification JSON File
This documentation is in a JSON format that can be accessible directly from your API’s swagger URL, as you can see below:
So let’s get back to our project, and see how can we enrich our API with proper documentation and configuration so that we can properly test the APIs (with authorization) directly from Swagger UI.
Adding Document Definition for the Endpoints in Swagger
Now let’s start by adding some details for the Tasks API, these details will be added within the AddSwaggerGen
method, as part of the SwaggerGenOptions. See the below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Version = "v1",
Title = "Tasks API",
Description = "Authorized Tasks API using JWT Authentication and refresh Tokens",
TermsOfService = new Uri("http://codingsonata.com/terms"),
Contact = new Microsoft.OpenApi.Models.OpenApiContact
{
Name = "Contact us",
Url = new Uri("http://codingsonata.com/contact"),
Email = "aram@codingsonata.com"
},
License = new Microsoft.OpenApi.Models.OpenApiLicense
{
Name = "License",
Url = new Uri("http://codingsonata.com/")
}
});
});
|
These details will be added to the generated OpenAPI specification file, and so it will be showing in the Swagger UI underneath the Tasks API header.
Press F5 in VS and see the browser showing the swagger UI with the new documentation for the Tasks API:
Adding Request/Response Types in Swagger
It would be great to have our endpoints show what are the possible responses of the endpoint as well as what types of request and response the endpoint will consume and produce respectively.
We need to add some attributes or data annotations on the endpoint level inside the controllers to better document and illustrate how the usage of the endpoint will, so let’s take an example like the Users endpoint:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
[HttpPost]
[Route("login")]
public async Task Login(LoginRequest loginRequest)
{
if (loginRequest == null || string.IsNullOrEmpty(loginRequest.Email) || string.IsNullOrEmpty(loginRequest.Password))
{
return BadRequest(new TokenResponse
{
Error = "Missing login details",
ErrorCode = "L01"
});
}
var loginResponse = await userService.LoginAsync(loginRequest);
if (!loginResponse.Success)
{
return Unauthorized(new
{
loginResponse.ErrorCode,
loginResponse.Error
});
}
return Ok(loginResponse);
}
|
We can see that this endpoint produces 3 different responses: 400, 401 and 200
and all the response types will be serialized as json from the TokenResponse Type.
and also for the request, it will also be deserialized from json to the the LoginRequest Type
So here we need to add Consumes, Produces, and ProducesResponseType attributes, as shown below:
1
2
3
4
5
6
7
|
[HttpPost]
[Route("login")]
[Consumes("application/json")]
[Produces("application/json")]
[ProducesResponseType(typeof(TokenResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(TokenResponse), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(TokenResponse), StatusCodes.Status200OK)]
|
So, the Consumes attribute tells us that this endpoint can accept data with content-type (media type) as application/json
and the Produces attribute defines the format of the response type, and he we set it as application/json as well.
The ProducesResponseType defines the type of response that will be associated with the expected status code, so if your endpoint will return multiple status codes,like in our case we have 400, 401 and 200, then we can define the types for each status code
Adding Security Definition and Security Requirement in Swagger
Let’s add the security definition and the security requirement for the authorization header so that the generated Swagger OpenApi Specification file would have the proper documentation to tell about the security specifications for the authorized endpoints.
Open program.cs file and inside the AddSwaggerGen
section, add the below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
options.AddSecurityDefinition("JWT Bearer", new OpenApiSecurityScheme
{
Description = "This is a JWT bearer authentication scheme",
In = ParameterLocation.Header,
Scheme = "Bearer",
Type = Microsoft.OpenApi.Models.SecuritySchemeType.Http
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme{
Reference = new OpenApiReference{
Id = "JWT Bearer",
Type = ReferenceType.SecurityScheme
}
}, new List<string>()
}
});
|
Here we are doing 2 things, defining the Security Scheme as an http header of type Bearer. Bearer means the bearer or the carrier of the authorization. Which says that we want to authorize the request that is carrying this token.
The second thing is that we are defining the security requirement where we are referencing the previous security definition using its name ‘JWT Bearer’ as the id to match it with the security requirement.
Testing the Security Configurations
Now let’s try to run our API and see how Swagger UI will display the authentication headers:
Notice in the above screen, we now have a new button with name ‘Authorize’ and a lock beside it. You can use this button to fill in the token that is generated from your token generation endpoint
So let’s generate a token using our /login endpoint
Now take this token and use it in the Authorize Button to let swagger UI use it in its requests for the protected endpoint
After pasting your token in the value field, press on Authorize and notice that it will display the value masked and that your token has been saved for the subsequent requests:
Now whenever you call any request, it will include the Authorization Header with the value as ‘Bearer {access_token} ‘
Note the lock icon beside each endpoint
So let’s try to test one of the protected endpoints for example the Get Tasks endpoint
If you logout and try to access the same endpoint you will get 401
Adding Header Filter in Swagger
Let’s say you are supporting localization in your ASP.NET Core Web API project and you want your clients to know about this feature, so with filters in Swagger you can add parameters to your operations or methods to describe the type, name and format of your input or request parameter.
So head back to the project, create a new folder with name Filters
and inside it create a new class with name AcceptLanguageOperationFilter
Add the below code in the class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace TasksApi.Filters
{
public class AcceptLanguageHeaderFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (operation == null)
{
throw new Exception("Invalid operation");
}
operation.Parameters.Add(new OpenApiParameter
{
In = ParameterLocation.Header,
Name = "accept-language",
Description = "pass the locale here: examples like => ar,ar-jo,en,en-gb",
Schema = new OpenApiSchema
{
Type = "String"
}
});
}
}
}
|
Then open program.cs
file, and add the below line within the end of AddSwaggerGen
method to configure the new OperationFilter
1 |
options.OperationFilter<AcceptLanguageHeaderFilter>();
|
This is ready now, press F5 to run the project and see the Swagger UI updating the endpoints with a new Accept-Language Header for the language input
If you want to know how to implement localization with a full implementation and step by step instructions, Check my tutorial Localization in ASP.NET Core Web API
Multipart/form-data and File Upload in Swagger
It is super easy to implement file upload with data with Swagger in ASP.NET Core Web API.
Decorating the endpoint parameter with [FromForm]
attribute will allow Swagger to detect the content-type of the endpoint and show it as multipart/form-data.
So let’s test it together.
Go back to the solution explorer and inside the Requests
Folder add a new class with name PostRequest
, and inside it add the below class, just don’t worry about the details we just need to showcase how Swagger will treat the [FromForm]
attribute:
1
2
3
4
5
6
7
8
9
|
namespace TasksApi.Requests
{
public class PostRequest
{
public int UserId { get; set; }
public string? Description { get; set; }
public IFormFile Image { get; set; }
}
}
|
Now, create a new Controller with name PostsRequest
and add the below code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using TasksApi.Requests;
using TasksApi.Responses;
namespace TasksApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class PostsController : ControllerBase
{
[HttpPost]
[Route("")]
[RequestSizeLimit(5 * 1024 * 1024)]
public IActionResult SubmitPost([FromForm] PostRequest postRequest)
{
if (postRequest == null)
{
return BadRequest(new BaseResponse { Success = false, ErrorCode = "S01", Error = "Invalid post request" });
}
if (string.IsNullOrEmpty(Request.GetMultipartBoundary()))
{
return BadRequest(new BaseResponse { Success = false, ErrorCode = "S02", Error = "Invalid post header" });
}
if (postRequest.Image != null)
{
// Code to save the image in storage
}
// Code to save the post in db
return Ok();
}
}
}
|
Let’s run the project and see how it will look like in Swagger UI:
Now try to browse a file and input some data in UserId and description, and hit Execute.
Notice the Curl how it is showing the request Content-Type as multipart/form-data and below it you can also see the key/value pairs of form-data being sent over the http request.
I have a complete tutorial to teach you how can you implement File Upload with Data using ASP.NET Core Web API , check it out and let me know what you think.
The tutorial is in .NET 6, you can feel free to read it and try it out since .NET 6 is still under LTS until November 2024, nevertheless, I will be updating my tutorials to .NET 7 gradually over the next few weeks.
Summary
In this tutorial we learned about Swagger OpenAPI specification and how can we integrate our ASP.NET Core Web API to define and configure the Swagger documentation. We learned how to define the general document, how to add request/response definitions, how to create security definition and requirement and finally we got introduced to the operation filter to learn how to add input parameter like an accept-language header as part of the request headers.
Please let me know in the comments your thoughts on this tutorial, and please share it in your network to help your developer friends and colleagues learn about implementing Swagger in ASP.NET Core Web API.
Check the Swagger official website to explore many resources and tools with regards API development.
Also take a look at the official website of OpenAPI Initiative to learn more about this initiative and the latest updates regarding the OpenAPI specification and other updates from the community behind it.
Want to learn ASP.NET Core Web API, check some of my tutorials below:
- Apply JWT Access Tokens and Refresh Tokens in ASP.NET Core Web API
- A Quick Guide to Learn ASP.NET Core Web API
- Boost your Web API Security with These Tips
- Logging with Serilog in ASP.NET Core Web API
- File Upload with Data using ASP.NET Core Web API
Subscribe to my newsletters to receive notifications on new articles and tutorials.
Bonus
Have you ever listened to this brilliant rendition of Henry Purcell’s Rondeau from Abdelazer (Z570) by Voices of Music?
Check it out and let me know if you like it.
Happy Coding and Listening 🙂