Skip to content

Commit ba437c5

Browse files
author
Jennifer Deigendesch
committed
Added swagger
1 parent 78029e5 commit ba437c5

File tree

8 files changed

+200
-8
lines changed

8 files changed

+200
-8
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# ASP.NET Core Example
22
This is an example of an REST API with ASP.NET Core v1.0, which is made via following tutorials:
33
Channel9: Creating REST API with ASP.NET Core (german): https://www.microsoft.com/germany/techwiese/know-how/video.aspx?id=msdn_de_67138
4-
Managing Static Files in ASP.NET Core: https://www.youtube.com/watch?v=n3rL0ekYEOM
4+
Managing Static Files in ASP.NET Core: https://www.youtube.com/watch?v=n3rL0ekYEOM
5+
ASP.NET Web API Help Pages using Swagger: https://docs.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger

src/ASPNETCoreExample/Controllers/FoodController.cs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,65 @@
1111

1212
using Repositories;
1313

14+
/// <summary>
15+
/// Controller of <see cref="IFoodRepository"/>.
16+
/// </summary>
1417
[Route("api/[controller]")]
1518
public class FoodController : Controller {
1619
private readonly IFoodRepository foodRepository;
1720

21+
/// <summary>
22+
/// Constructor
23+
/// </summary>
24+
/// <param name="foodRepository">Repository of <see cref="FoodItem"/>.</param>
1825
public FoodController(IFoodRepository foodRepository) {
1926
this.foodRepository = foodRepository;
2027
}
2128

29+
/// <summary>
30+
/// Get all items of food.
31+
/// </summary>
32+
/// <returns>All items of food.</returns>
33+
/// <response code="200">Returns all items of food.</response>
2234
[HttpGet]
35+
[ProducesResponseType(typeof(IEnumerable<FoodDto>), 200)]
2336
public IActionResult GetAllFoodItems() {
2437
ICollection<FoodItem> foodItems = this.foodRepository.GetAll();
2538
IEnumerable<FoodDto> mappedItems = foodItems.Select(AutoMapper.Mapper.Map<FoodDto>);
2639

2740
return this.Ok(mappedItems);
2841
}
2942

43+
/// <summary>
44+
/// Get a single food item of given <paramref name="id"/>.
45+
/// </summary>
46+
/// <param name="id">Id of the <see cref="FoodItem"/> to get.</param>
47+
/// <returns><see cref="FoodItem"/> of given <paramref name="id"/>.</returns>
48+
/// <response code="404">If the item cannot be found.</response>
49+
/// <response code="200">Returns the single food item.</response>
3050
[HttpGet("{id:int}", Name = "GetSingleFoodItem")]
51+
[ProducesResponseType(typeof(FoodDto), 404)]
52+
[ProducesResponseType(typeof(FoodDto), 200)]
3153
public IActionResult GetSingleFoodItem(int id) {
3254
FoodItem foodItem = this.foodRepository.GetSingle(id);
3355

3456
if (foodItem == null) {
3557
return this.NotFound();
3658
}
3759

38-
return this.Ok(AutoMapper.Mapper.Map<FoodItem>(foodItem));
60+
return this.Ok(AutoMapper.Mapper.Map<FoodDto>(foodItem));
3961
}
4062

63+
/// <summary>
64+
/// Add a new food item.
65+
/// </summary>
66+
/// <param name="foodDto">Mapped <see cref="FoodItem"/> to add.</param>
67+
/// <returns>Link to get the food item, which was added and also the added <see cref="FoodDto"/> object.</returns>
68+
/// <response code="400">If the given food item is null or invalid.</response>
69+
/// <response code="201">Returns the created food item.</response>
4170
[HttpPost]
71+
[ProducesResponseType(typeof(FoodDto), 400)]
72+
[ProducesResponseType(typeof(FoodDto), 201)]
4273
public IActionResult AddNewFoodItem([FromBody] FoodDto foodDto) {
4374
if (foodDto == null) {
4475
return this.BadRequest();
@@ -58,7 +89,19 @@ public IActionResult AddNewFoodItem([FromBody] FoodDto foodDto) {
5889
AutoMapper.Mapper.Map<FoodDto>(foodItem));
5990
}
6091

92+
/// <summary>
93+
/// Update the given food item with the food item of the given <paramref name="id"/>.
94+
/// </summary>
95+
/// <param name="id">Id of the <see cref="FoodItem"/> to update.</param>
96+
/// <param name="foodDto">New values of the <see cref="FoodItem"/> to update.</param>
97+
/// <returns>Updated <see cref="FoodDto"/> object.</returns>
98+
/// <response code="404">If the given food item cannot be found.</response>
99+
/// <response code="400">If the given id doesn't match the id of the given food item or the given food item is invalid.</response>
100+
/// <response code="200">Returns the updated food item.</response>
61101
[HttpPut("{id:int}")]
102+
[ProducesResponseType(typeof(FoodDto), 404)]
103+
[ProducesResponseType(typeof(FoodDto), 400)]
104+
[ProducesResponseType(typeof(FoodDto), 200)]
62105
public IActionResult UpdateFoodItem(int id, [FromBody] FoodDto foodDto) {
63106
var foodItemToCheck = this.foodRepository.GetSingle(id);
64107
if (foodItemToCheck == null) {
@@ -77,7 +120,19 @@ public IActionResult UpdateFoodItem(int id, [FromBody] FoodDto foodDto) {
77120
return this.Ok(AutoMapper.Mapper.Map<FoodDto>(foodItem));
78121
}
79122

123+
/// <summary>
124+
/// Partial update the given food data with the food item of the given <paramref name="id"/>.
125+
/// </summary>
126+
/// <param name="id">Id of the <see cref="FoodItem"/> to partial update.</param>
127+
/// <param name="foodDtoPatchDoc">New values of the <see cref="FoodItem"/> to partial update.</param>
128+
/// <returns>Updated <see cref="FoodDto"/> object.</returns>
129+
/// <response code="400">If the given food data is null or invalid.</response>
130+
/// <response code="404">If the food item with the given id cannot be found.</response>
131+
/// <response code="200">Returns the partial updated food item.</response>
80132
[HttpPatch("{id:int}")]
133+
[ProducesResponseType(typeof(FoodDto), 400)]
134+
[ProducesResponseType(typeof(FoodDto), 404)]
135+
[ProducesResponseType(typeof(FoodDto), 200)]
81136
public IActionResult PartialUpdate(int id, [FromBody] JsonPatchDocument<FoodDto> foodDtoPatchDoc) {
82137
if (foodDtoPatchDoc == null) {
83138
return this.BadRequest();
@@ -99,7 +154,16 @@ public IActionResult PartialUpdate(int id, [FromBody] JsonPatchDocument<FoodDto>
99154
return this.Ok(AutoMapper.Mapper.Map<FoodDto>(foodItem));
100155
}
101156

157+
/// <summary>
158+
/// Remove the food item with the given <paramref name="id"/>.
159+
/// </summary>
160+
/// <param name="id">Id of the <see cref="FoodItem"/> to remove.</param>
161+
/// <returns>Nothing.</returns>
162+
/// <response code="404">If the food item with the given id cannot be found.</response>
163+
/// <response code="204">If the food item of the given id was successfully deleted.</response>
102164
[HttpDelete("{id:int}")]
165+
[ProducesResponseType(typeof(FoodDto), 404)]
166+
[ProducesResponseType(typeof(FoodDto), 204)]
103167
public IActionResult Remove(int id) {
104168
var foodItem = this.foodRepository.GetSingle(id);
105169
if (foodItem == null) {

src/ASPNETCoreExample/Dtos/FoodDto.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,42 @@
22
using System;
33
using System.ComponentModel.DataAnnotations;
44

5+
using ASPNETCoreExample.Models;
6+
7+
/// <summary>
8+
/// Data transfer object of <see cref="FoodItem"/>.
9+
/// </summary>
510
public class FoodDto {
11+
/// <summary>
12+
/// Unique id.
13+
/// </summary>
614
public int Id {
715
get;
816
set;
917
}
1018

19+
/// <summary>
20+
/// Name of the given item.
21+
/// </summary>
1122
[Required]
1223
public string Name {
1324
get;
1425
set;
1526
}
1627

28+
/// <summary>
29+
/// Calories of the given item.
30+
/// </summary>
1731
[Required]
1832
[Range(0, 1000, ErrorMessage = "Das sind zu viele Kalorien für dich!!")]
1933
public int Calories {
2034
get;
2135
set;
2236
}
2337

38+
/// <summary>
39+
/// Time when the given item is created.
40+
/// </summary>
2441
public DateTime Created {
2542
get;
2643
set;

src/ASPNETCoreExample/Models/FoodItem.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,39 @@
11
namespace ASPNETCoreExample.Models {
22
using System;
33

4+
using ASPNETCoreExample.Repositories;
5+
6+
/// <summary>
7+
/// Model of <see cref="FoodRepository"/>.
8+
/// </summary>
49
public class FoodItem {
10+
/// <summary>
11+
/// Unique id.
12+
/// </summary>
513
public int Id {
614
get;
715
set;
816
}
917

18+
/// <summary>
19+
/// Name of the given item.
20+
/// </summary>
1021
public string Name {
1122
get;
1223
set;
1324
}
1425

26+
/// <summary>
27+
/// Calories of the given item.
28+
/// </summary>
1529
public int Calories {
1630
get;
1731
set;
1832
}
1933

34+
/// <summary>
35+
/// Time when the given item is created.
36+
/// </summary>
2037
public DateTime Created {
2138
get;
2239
set;

src/ASPNETCoreExample/Program.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33

44
using Microsoft.AspNetCore.Hosting;
55

6+
/// <summary>
7+
/// Main class.
8+
/// </summary>
69
public class Program {
10+
/// <summary>
11+
/// Main method.
12+
/// </summary>
13+
/// <param name="args"></param>
714
public static void Main(string[] args) {
815
var host =
916
new WebHostBuilder().UseKestrel()

src/ASPNETCoreExample/Repositories/FoodRepository.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,28 @@
66

77
using Models;
88

9+
/// <summary>
10+
/// Repository of <see cref="FoodItem"/>.
11+
/// </summary>
912
public class FoodRepository : IFoodRepository {
1013
private readonly ConcurrentDictionary<int, FoodItem> storage = new ConcurrentDictionary<int, FoodItem>();
1114

15+
/// <summary>
16+
/// Get a single <see cref="FoodItem"/> with given <paramref name="id"/>.
17+
/// </summary>
18+
/// <param name="id">Id of the <see cref="FoodItem"/> to get.</param>
19+
/// <returns><see cref="FoodItem"/> with given <paramref name="id"/></returns>
1220
public FoodItem GetSingle(int id) {
1321
FoodItem item;
1422
return this.storage.TryGetValue(id, out item) ? item : null;
1523
}
1624

25+
/// <summary>
26+
/// Add given <see cref="FoodItem"/>.
27+
/// </summary>
28+
/// <param name="item"><see cref="FoodItem"/> to add.</param>
29+
/// <returns>Added <see cref="FoodItem"/>.</returns>
30+
/// <exception cref="Exception"></exception>
1731
public FoodItem Add(FoodItem item) {
1832
item.Id = !this.GetAll().Any() ? 1 : this.GetAll().Max(value => value.Id) + 1;
1933

@@ -24,6 +38,11 @@ public FoodItem Add(FoodItem item) {
2438
throw new Exception("Item could not be added.");
2539
}
2640

41+
/// <summary>
42+
/// Delete <see cref="FoodItem"/> with given <paramref name="id"/>.
43+
/// </summary>
44+
/// <param name="id">Id of the <see cref="FoodItem"/> to delete.</param>
45+
/// <exception cref="Exception"></exception>
2746
public void Delete(int id) {
2847
FoodItem item;
2948

@@ -32,15 +51,29 @@ public void Delete(int id) {
3251
}
3352
}
3453

54+
/// <summary>
55+
/// Update the values of given <paramref name="item"/> for <see cref="FoodItem"/> with given <paramref name="id"/>.
56+
/// </summary>
57+
/// <param name="id">Id of the <see cref="FoodItem"/> to update.</param>
58+
/// <param name="item">New values of the <see cref="FoodItem"/> to update.</param>
59+
/// <returns>Updated <see cref="FoodItem"/>.</returns>
3560
public FoodItem Update(int id, FoodItem item) {
3661
this.storage.TryUpdate(id, item, this.GetSingle(id));
3762
return item;
3863
}
3964

65+
/// <summary>
66+
/// Get all available <see cref="FoodItem"/>.
67+
/// </summary>
68+
/// <returns>Collection of <see cref="FoodItem"/>.</returns>
4069
public ICollection<FoodItem> GetAll() {
4170
return this.storage.Values;
4271
}
4372

73+
/// <summary>
74+
/// Count of <see cref="FoodItem"/> available within the storage.
75+
/// </summary>
76+
/// <returns>Count of <see cref="FoodItem"/> available within the storage.</returns>
4477
public int Count() {
4578
return this.storage.Count;
4679
}

src/ASPNETCoreExample/Startup.cs

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,55 @@
11
namespace ASPNETCoreExample {
2+
using System.IO;
3+
24
using Dtos;
35

46
using Microsoft.AspNetCore.Builder;
57
using Microsoft.AspNetCore.Hosting;
68
using Microsoft.Extensions.DependencyInjection;
79
using Microsoft.Extensions.Logging;
10+
using Microsoft.Extensions.PlatformAbstractions;
811

912
using Models;
1013

1114
using Repositories;
1215

16+
using Swashbuckle.Swagger.Model;
17+
18+
/// <summary>
19+
/// Start class of the API.
20+
/// </summary>
1321
public class Startup {
14-
// This method gets called by the runtime. Use this method to add services to the container.
15-
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
22+
/// <summary>
23+
/// This method gets called by the runtime. Use this method to add services to the container.
24+
/// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
25+
/// </summary>
26+
/// <param name="services"></param>
1627
public void ConfigureServices(IServiceCollection services) {
1728
services.AddSingleton<IFoodRepository, FoodRepository>();
1829
services.AddMvc();
30+
31+
// Inject an implementation of ISwaggerProvider with defaulted settings applied
32+
services.AddSwaggerGen();
33+
34+
services.ConfigureSwaggerGen(
35+
options => {
36+
options.SingleApiVersion(CreateSwaggerInfo());
37+
38+
// Determine base path for the application.
39+
string basePath = PlatformServices.Default.Application.ApplicationBasePath;
40+
41+
// Set the comments path for the swagger json and ui.
42+
string xmlPath = Path.Combine(basePath, "ASPNETCoreExample.xml");
43+
options.IncludeXmlComments(xmlPath);
44+
});
1945
}
2046

21-
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
47+
/// <summary>
48+
/// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
49+
/// </summary>
50+
/// <param name="app"></param>
51+
/// <param name="env"></param>
52+
/// <param name="loggerFactory"></param>
2253
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
2354
loggerFactory.AddConsole();
2455

@@ -33,6 +64,12 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
3364
app.UseFileServer();
3465

3566
InitMapper();
67+
68+
// Enable middleware to serve generated Swagger as a JSON endpoint
69+
app.UseSwagger();
70+
71+
// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
72+
app.UseSwaggerUi();
3673
}
3774

3875
private static DefaultFilesOptions CreateDefaultFilesOptions() {
@@ -49,5 +86,19 @@ private static void InitMapper() {
4986
mapper.CreateMap<FoodItem, FoodDto>().ReverseMap();
5087
});
5188
}
89+
90+
private static Info CreateSwaggerInfo() {
91+
return new Info {
92+
Version = "v1",
93+
Title = "ASP.NET Core v1.0 API",
94+
Description = "This is an example of a REST API with ASP.NET Core v1.0",
95+
TermsOfService = "None",
96+
Contact = new Contact {
97+
Name = "Jennifer Deigendesch",
98+
Email = "[email protected]",
99+
Url = "https://github.com/doubleSlashde/ASPNETCoreExample"
100+
}
101+
};
102+
}
52103
}
53104
}

0 commit comments

Comments
 (0)