Designing Flexible and Cross-Platform API using Asp.Net Core — Part 2

Nermin Kaharovic
May 10, 2019 · 5 min read
Image for post
Image for post

This is a two-part guide for designing flexible and cross-platform API using ASP.NET Core. You can read Part 1 here.

In this part, we will explain how to configure API middleware and other services. Following this, we will explain how to test everything using Swagger.

Middleware configuration

ASP.NET Core applications start inside of Program.cs and after initial configuration is completed, Startup.cs is initiated. We use ConfigureServices method inside of Startup class to define services that our application will use. All third party libraries configuration, as well as other service initialization, will be placed here.

// Dependency injection - fluent validation
services.AddSingleton<IValidator<UserRegisterDto>,
AddUserDtoValidator>();
// Override Modelstate behavior
// Aggregate valdiation errors
services.Configure<ApiBehaviorOptions>(options =>{
options.InvalidModelStateResponseFactory = (context) =>
{
var errors = context.ModelState.Values.SelectMany(x =>
x.Errors.Select(p => p.ErrorMessage)).ToList();

var result = new
{
Code = "400", // BadRequest error code
Message = "Validation errors",
Errors = errors
};
return new BadRequestObjectResult(result);
};});
// SQL provider configuration
services.AddDbContext<DataContext>(x => x.UseSqlite
(Configuration.GetConnectionString("DefaultConnection")));

// Dependency injection - repositories
services.AddScoped<IAuthentificationRepository,
AuthRepository>();
services.AddScoped<IBookRepository, BooksRepository>();// JWT token authentification set up
services.AddAuthentication
(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
var token = Encoding.ASCII.GetBytes(
Configuration.GetSection("AppSettings:Token").Value);
options.TokenValidationParameters = new
TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(token),
ValidateIssuer = false,
ValidateAudience = false
};
});
// AutoMapper initialization
services.AddAutoMapper();}
// Register the Swagger generator, defining 1 or more Swagger
documents
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new Info
{
Title = "WebApp.API",
Version = "v1"
});
c.AddSecurityDefinition("Bearer", new ApiKeyScheme
{
In = "header",
Description = "Please enter JWT with Bearer into field",
Name = "Authorization",
Type = "apiKey"
});

c.AddSecurityRequirement(new Dictionary<string,
IEnumerable<string>>
{
{ "Bearer", Enumerable.Empty<string>() }
});
});

services.AddCors();
}

Next, modify Configure method. This is the place where we typically use IApplicationBuilder to set up our middleware.

˛          var contextFeature =  
context.Features.Get<IExceptionHandlerFeature>();
if (contextFeature != null)
{
// Log error
// Write response
await context.Response
.WriteAsync(contextFeature.Error.Message);
}});
});
app.UseHttps();}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseSwagger();

// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
app.UseMvc();
}

We configured authentication and Swagger. In addition to that, we created a global exception handler to make API actions more readable and the error handling process more maintainable.

Test API

Once we have created API and set up all the necessary tools, the only thing left is to test it.

Registration

Let’s create a POST request in order to set up a new User:

Image for post
Image for post
Picture 1 - Registration request

After the request has been submitted, we’ll get 201 code and the user should be inserted into the database.

Image for post
Image for post
Picture 2 - Registration response

Authentication

In order to authenticate user, we need to send a valid username/password combination:

Image for post
Image for post
Picture 3 - Login request

If the user is successfully authenticated, the response will contain JWT token:

Image for post
Image for post
Picture 4 - Login response

Retrieve data

Now when we try to access Books controller that requires an authorization, we’ll receive 401 Unauthorized error code:

Image for post
Image for post
Picture 5 - Response - Unauthorized request

In order to pass authorization, we need to include Bearer token in our request. In order to do this with Swagger, we’ll need some additional configuration in the Swagger generator:

services.AddSwaggerGen(c =>
{
...
c.AddSecurityDefinition("Bearer", new ApiKeyScheme
{
In = "header",
Description = "Please enter JWT with Bearer into field",
Name = "Authorization",
Type = "apiKey"
});

c.AddSecurityRequirement(new Dictionary<string,
IEnumerable<string>>
{
{ "Bearer", Enumerable.Empty<string>() }
});
});

We should see an Authorize button in the upper right corner where we can enter authorization data:

Image for post
Image for post
Picture 6 - API methods

Enter token that was previously retrieved with Login action:

Image for post
Image for post
Picture 7 - Authorization token

Now, when we submit the request, we should get a response with valid data. This means the user was successfully authorized.

Image for post
Image for post
Picture 8 - Successful response

Conclusion

We hope you’ll find this two-part guide for designing a flexible and cross-platform API useful. In the end, I’d like to point out that this is not a bullet-proof solution, and it might not cover all your needs for “Production ready API”, but it will definitely give you an idea how to start with building a flexible, extensible and maintainable API using ASP.NET Core.

This will give you a headstart and you’ll get a basic overview of:

  • Implementing authentification,
  • Creating model validation,
  • Repositories,
  • Generic error handler
  • Data mappings between ORM entities and DTO’s,
  • Developing and testing with Swagger,
  • Implementing asynchronous data transfer.

That’s it for now! Feel free to share any thoughts or questions you may have.

Maestral Solutions

Product Development as a Service (PDaaS) partner, living…

Nermin Kaharovic

Written by

Full Stack Software Developer, Microsoft Certified Professional, and Technical Blog Writer

Maestral Solutions

Product Development as a Service (PDaaS) partner, living and breathing our core values of “People First” & “Culture of Trust”.

Nermin Kaharovic

Written by

Full Stack Software Developer, Microsoft Certified Professional, and Technical Blog Writer

Maestral Solutions

Product Development as a Service (PDaaS) partner, living and breathing our core values of “People First” & “Culture of Trust”.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store