.Net Core Üzerinde Swagger
Selamlar,
Bu makalede doğan bir ihtiyaca göre kullandığım teknolojilerden, Swagger üzerine konuşacağız. Şirket içinde kullanılan ya da dışarıya açılan WebServislerinin, bazen anlaşılması zor olabilir. Post ve Get methodları hangileridir? Post’da istenen model ve propertyler nelerdir? Get’de istenen parametreler nedir? Geri dönüş değerleri nelerdir? Bu ve bunun gibi ihtiyaçlar için detaylı bir dökümanın hazırlanması ve her yeni method’da ilgili dökümanın güncellenerek paylaşılması gerekmektedir. İşte bu noktada Swagger devreye girmektedir. Gelin hep beraber bir örnek üzerinde swagger’ı canlı canlı inceleyelim.
Okulların yeni başladığı bu dönemde .Net Core WebApi bir SchollService projesi oluşturalım.
1 |
dotnet new webapi -o swaggerCore |
Bu projede amaç sınıflar ve öğrencilerin sorgulandığı ve güncellendiği bir webapi servisi oluşturmaktır.
Models:
- Class.cs:
1 2 3 4 5 6 |
public class Class{ public int ID { get; set; } public string Name { get; set; } public string TeacherName { get; set; } public int Population { get; set; } } |
- Student.cs
1 2 3 4 5 6 7 8 |
public class Student{ public int ID { get; set; } public string Name { get; set; } public int No { get; set; } public string Gender { get; set; } public int Age { get; set; } public int ClassID { get; set; } } |
Şimdi sıra Bussines’ın döndüğü Data tarafında.
DAL:
- ISchollService: Yapılacak tüm işler, bir interface altında toplanmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System.Collections.Generic; public interface ISchollService { List<Class> GetAllClass(); Class GetClassByID(int id); Class GetClassByName(string Name); List<Student> GetAllStudents(); List<Student> GetStudentByClass(int classID); Student GetStudentByID(int ID); Student GetStudentByName(string Name); void AddStudent(Student student); void AddClass(Class _class); } |
- SchollService: Datalar, static bir listeden örnek amaçlı çekilmektedir. Okul ve öğrenci listeleme, ya da filitreleme gibi işlemlerin yapıldığı örnek amaçlı birden çok servis oluşturulmuştur. Ayrıca yeni öğrenci ve sınıf girişinin yapıldığı iki “Post” servis yazılmıştır.
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
using System.Collections.Generic; using System.Threading.Tasks; public class SchollService : ISchollService { public static List<Class> classList = new List<Class>(){ new Class(){ID=1,Name="1-A",Population=30,TeacherName="X Bayan"}, new Class(){ID=2,Name="1-B",Population=20,TeacherName="Y Bayan"}, new Class(){ID=3,Name="2-A",Population=22,TeacherName="Z Erkek"}, new Class(){ID=4,Name="2-B",Population=32,TeacherName="No name"}, }; public static List<Student> studentList = new List<Student>(){ new Student(){ID=1,Name="Abc",Age=6,Gender="Kız",No=111,ClassID=1}, new Student(){ID=2,Name="XXX",Age=5,Gender="Erkek",No=222,ClassID=1}, new Student(){ID=3,Name="YYY",Age=7,Gender="Erkek",No=333,ClassID=2}, new Student(){ID=4,Name="ZZZZ",Age=6,Gender="kız",No=444,ClassID=2} }; public List<Class> GetAllClass() { return classList; } public List<Student> GetAllStudents() { return studentList; } public Class GetClassByID(int id) { return classList.Find(result => result.ID == id); } public Class GetClassByName(string name) { return classList.Find(result => result.Name == name); } public List<Student> GetStudentByClass(int classID) { return studentList.FindAll(result => result.ClassID == classID); } public Student GetStudentByID(int ID) { return studentList.Find(result => result.ID == ID); } public Student GetStudentByName(string Name) { return studentList.Find(result => result.Name == Name); } public void AddStudent(Student student) { studentList.Add(student); } public void AddClass(Class _class) { classList.Add(_class); } } |
Şimdi sıra geldi WebApi servisini oluşturmaya:
SchollController.cs: Aşağıda görüldüğü gibidir.
- GetAllClass(): Tüm sınıfların çekildiği method “[HttpGet(“GetAllClass”)]” şeklinde routing amaçlı tanımlanmıştır. Dönüş tipi ==>”List<Class>”‘dır.
- GetAllStudents(): Tüm öğrencilerin çekildiği method “[HttpGet(“GetAllStudents”)]” şeklinde tanımlanmıştır. Dönüş tipi ==>”<List<Student>>”‘dır.
- GetClassByID(int id): Bir sınıfın “id” değerine göre çağrıldığı bir methoddur. “[HttpGet(“GetClassByID/{id}”)]” şeklinde tanımlanmıştır. Dönüş tipi ==>”Class”‘dır.
- GetClassByName(string name): Bir sınıfın “name” yani adına göre çağrıldığı bir methoddur. ” [HttpGet(“GetClassByName/{name}”)]” şeklinde tanımlanmıştır. Dönüş tipi ==>”Class”‘dır.
- GetStudentByClass(int classID) : Bir öğrencinin “classID” değerine göre çağrıldığı bir methoddur. “[HttpGet(“GetStudentByClass/{classID}”)]” şeklinde tanımlanmıştır. Dönüş tipi ==>”List<Student>”‘dır.
- GetStudentByID(int id) : Bir öğrencinin “id” değerine göre çağrıldığı bir methoddur. “[HttpGet(“GetStudentByID/{id}”)]” şeklinde tanımlanmıştır. Dönüş tipi ==>”Student”‘dır.
- GetStudentByName(string name) : Bir öğrencinin “name” yani adına göre çağrıldığı bir methoddur. “[HttpGet(“GetStudentByName/{id}”)]” şeklinde tanımlanmıştır. Dönüş tipi ==> “Student”‘dır.
- AddStudent([FromBody] Student student) : Yeni bir öğrencinin kaydedildiği methodur. “[HttpPost(“AddStudent”)]” şeklinde tanımlanmıştır.
- AddClass([FromBody] Class _class): Yeni bir sınıfın kaydedildiği methoddur. “[HttpPost(“AddClass”)]” şeklinde tanımlanmıştır.
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; namespace swaggerCore.Controllers { [Route("api/[controller]")] [ApiController] public class SchollController : ControllerBase { SchollService schollService; public SchollController() { schollService = new SchollService(); } // GET api/GetAllClass [HttpGet("GetAllClass")] public ActionResult<List<Class>> GetAllClass() { return schollService.GetAllClass(); } [HttpGet("GetAllStudents")] public ActionResult<List<Student>> GetAllStudents() { return schollService.GetAllStudents(); } [HttpGet("GetClassByID/{id}")] public Class GetClassByID(int id) { return schollService.GetClassByID(id); } [HttpGet("GetClassByName/{name}")] public Class GetClassByName(string name) { return schollService.GetClassByName(name); } [HttpGet("GetStudentByClass/{classID}")] public List<Student> GetStudentByClass(int classID) { return schollService.GetStudentByClass(classID); } [HttpGet("GetStudentByID/{id}")] public Student GetStudentByID(int id) { return schollService.GetStudentByID(id); } [HttpGet("GetStudentByName/{id}")] public Student GetStudentByName(string name) { return schollService.GetStudentByName(name); } [HttpPost("AddStudent")] public void AddStudent([FromBody] Student student) { schollService.AddStudent(student); } [HttpPost("AddClass")] public void AddClass([FromBody] Class _class) { schollService.AddClass(_class); } } } |
Bu kadar methodun, başka biri kullanıcı tarafından kolaylıkla kullanılabilmesi için, Swagger .Net Core ortamına aşağıdaki komut ile eklenir.
1 |
dotnet add package Swashbuckle.AspNetCore |
Sıra geldi .Net Core Ortamında Swagger’ın Startup.cs’de tanımlanmasına.
Startup.cs/ConfigureServices:
- “services.AddTransient<ISchollService, SchollService>()” ile servise yapılan her çağrıda yeni bir SchollService oluşturulur.
- “services.AddSwaggerGen(c =>” : Swagger .Net Core ortamında belli configurasyonlar ile tanımlanır.
- “c.SwaggerDoc(“CoreSwagger”, new Info” : CoreSwagger adı ile Başlık, versiyon, açıklama ve iletişim özellikleri ile service’e eklenir. Daha detaylı özellikleri sayfanın en altındaki kaynaktan edinebilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public void ConfigureServices(IServiceCollection services) { services.AddTransient<ISchollService, SchollService>(); services.AddSwaggerGen(c => { c.SwaggerDoc("CoreSwagger", new Info { Title = "Swagger on ASP.NET Core", Version = "1.0.0", Description = "Try Swagger on (ASP.NET Core 2.1)", Contact = new Contact() { Name = "Swagger Implementation Bora kasmer", Url = "http://borakasmer.com", Email = "bora@borakasmer.com" }, TermsOfService = "http://swagger.io/terms/" }); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } |
Startup.cs/Configure: Aşağıda görüldüğü gibi:
- app.UseSwagger(): .Net Core projesine swagger eklenmiştir.
- .UseSwaggerUI(c => {c.SwaggerEndpoint(“/swagger/CoreSwagger/swagger.json”, “Swagger Test .Net Core”);});: Burada swagger için kullanılacak “json” dosyasının kaydedileceği yer tanımlanmaktadır.
NOT: “/CoreSwagger” olarak yazılan kısım ==> yukarıda ConfigureServices’de tanımlanan “c.SwaggerDoc(“CoreSwagger“, new Info” ile aynı olmak zorundadır. Swagger’ın isim parametresi olarak kullanılmaktadır.
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 |
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseStaticFiles(); app.UseSwagger() .UseSwaggerUI(c => { //TODO: Either use the SwaggerGen generated Swagger contract (generated from C# classes) c.SwaggerEndpoint("/swagger/CoreSwagger/swagger.json", "Swagger Test .Net Core"); //TODO: Or alternatively use the original Swagger contract that's included in the static files // c.SwaggerEndpoint("/swagger-original.json", "Swagger Petstore Original"); }); app.UseHttpsRedirection(); app.UseMvc(); } |
Swagger sayfasına girilince WebApi Servisinde kullanılan methodlar, aşağıdaki gibi listelenmektedir.
Bundan sonra aşağıdaki adres satırı, bu webservisini kullanacak kişi ile paylaşılarak, kendini sürekli yenileyen, yani yeni bir servis eklendiğinde ya da değiştirildiğinde güncellenmesine gerek kalmayan bir helper olarak kullanılabilmektedir.
1 |
http://localhost:5500/swagger |
1 2 3 4 5 6 7 8 9 10 11 12 |
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>> { { "Bearer", new string[] { } } }); c.AddSecurityDefinition("Bearer", new ApiKeyScheme() { Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"", Name = "Authorization", In = "header", Type = "apiKey", }); |
Yukarıdaki tanımlamalar yapıldıktan sonra, Swagger ekranında aşağıda görülen istendiğinde token girilmesi için gerekli olan Authorize buttonu, karşımıza çıkmaktadır.
Örneğin Token için “446688” girildikten sonra “GetClassByID()” methodu çağrıldığında, WebApi servisine Header ile giden request aşağıdaki gibidir. Görüldüğü gibi girilen Token ==> “Authorization: 446688” şeklinde Header’dan, WebApi servisine taşınmaktadır.
1 |
curl -X GET "http://localhost:5500/api/Scholl/GetClassByID/2" -H "accept: text/plain" -H "Authorization: 446688" |
Şimdi gelin tüm Actionlar’da ilgili Token’ı yakalamak için, Custom bir TokenFilter yazalım.
TokenFilter.cs: Herbir Action’a girilmeden önce, Header ile gönderilen “Authorization” Token, aşağıda görüldüğü gibi örnek amaçlı yakalanmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using System; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; public class TokenFilter : IActionFilter { public void OnActionExecuted(ActionExecutedContext context) { } public void OnActionExecuting(ActionExecutingContext context) { string Token = context.HttpContext.Request.Headers["Authorization"]; Console.Write($"Token Değeri : {Token}"); } } |
İlgili TokenFilter’ın .Net Core’da kullanılabilmesi için, Startup/ConfigureService‘e aşağıdaki gibi eklenmesi gerekmektedir.
1 |
services.AddScoped<TokenFilter>(); |
SchollController.cs: İlgili TokenFilter’ın, SchollController’ın başına aşağıdaki gibi tanımlanması ile, ilgili Controller’ın içinde geçen tüm Actionlara girilmeden önce, TokenFilter/OnActionExecuting() methodu çalıştırılır.
1 2 3 4 |
[ServiceFilter(typeof(TokenFilter))] [Route("api/[controller]")] [ApiController] public class SchollController : ControllerBase |
Güncelleme – Swagger’da Header’a Custom Fieldlar Ekleme:
Eğer yapılan request üzerinde, Header’a farklı custom alanlar konulmak istenir ve bunların Swaggerdan da girilmesi gerekir ise, IOperationFilter interface’inden türeyen yeni bir sınıfın aşağıdaki gibi oluşturulması gerekmektedir.
Aşağıdaki örnekte WebApi servisinde yapılan Request’de, Header’a “isMobile” bool ve “senderName” string alanları eklenmiştir. Swaggerdan da “senderName” alanının girilmesi zorunlu, “isMobile” alanının girilmesi isteğe bağlı hale getirilmiştir.
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 |
using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; public class AddHeaderParameter : IOperationFilter { public void Apply(Operation operation, OperationFilterContext context) { if (operation.Parameters == null) operation.Parameters = new List<IParameter>(); operation.Parameters.Add(new NonBodyParameter { Name = "isMobile", In = "header", Type = "bool", Required = true, }); operation.Parameters.Add(new NonBodyParameter { Name = "senderName", In = "header", Type = "string", Required = true, }); } } |
Son olarak, yeni tanımlanan “OperationFilter” sınıfının, Startup.cs’de swagger’a eklenmesi gerekmektedir.
1 2 3 4 5 6 7 |
services.AddSwaggerGen(c => { . . . c.OperationFilter<AddHeaderParameter>(); }); |
Böylece Swagger üzerinden girilen Custom bir Token’ın, WebApi servisine Header ile nasıl taşındığını, ilgili Action’a girmeden önce nasıl yakalandığını ve son olarak Header’a nasıl custome fieldların eklendiğini gördük.
Swagger, özellikle günümüzde WebApi servislerinin bolca kullanıldığı, hatta bunların dışarıda bir kaynak ile paylaşıldığı yapılarda, dökümanı ortadan kaldıran basit, pratik ve vazgeçilmez bir tooldur.
Geldik bir makalenin daha sonuna yeni bir makalede görüşmek üzere hepinize hoşçakalın.
Source Code : https://github.com/borakasmer/SwaggerOnNetCore
Kaynaklar: http://editor.swagger.io, https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/428
Hocam elinize sağlık. Bunu görmüştüm ama adını unutmuştum sizde görünce tekrar hatırladım. Hemde keni projeme uygulamadım.
Ben teşekkür ederim :)
Merhaba öncelikle paylaşımınız için teşekkür ederim.
Projeyi Visual studio da açıp F5 lediğimde web api çalışmıyor Bora hocam
Source code da bir sıkıntı olabilir mi
Selamlar,
Kullanılan dll’lerin güncellenmesi gerekebilir.
Enfes anlatım! 5 dakikanın altında bir sürede uygulanabilir şekilde anlatmak herkesin harcı değil. Teşekkürler!
Teşekkür ederim :)