Web Api 中多數都會選擇RESTful Web API 設計
自己習慣自定義識別碼,並配合POST使用,沒有完全採用Http StatusCode作為狀態識別碼
所以需要Swagger改為配合自定義識別碼的使用
環境.Net 6
使用套件
- Swashbuckle.AspNetCore.Annotations
- Swashbuckle.AspNetCore.Filters
- Swashbuckle
需要解決的問題有
- 提供範例碼
- 列舉值識別碼
- Header中擺放Token
步驟
- 統一改用IActionResult並配合Ok Function帶入要回傳的Response
- 使用FromHeader 提取Header中的Token參數
- 使用SwaggerResponse作為Schema呈現
- 使用SwaggerResponseExample提供範例碼
- 在Program中加入ExampleFilters、AddSwaggerExamplesFromAssemblies,才可使用範例碼呈現
- 在Program中加入EnumTypesSchemaFilter,才可在Schema中呈現列舉值
新增Post回應的class
/// <summary>
/// Post 回應
/// </summary>
public class PostResponse
{
/// <summary>
/// 識別代碼
/// </summary>
public Code Code { get; set; }
/// <summary>
/// 訊息
/// </summary>
public string? Msg { get; set; }
/// <summary>
/// 氣象資料
/// Code = 0 時 此欄位才有值
/// </summary>
public WeatherForecast? Data { get; set; }
}
/// <summary>
/// 天氣預報
/// </summary>
public class WeatherForecast
{
/// <summary>
/// 時間
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// 攝氏
/// </summary>
public int TemperatureC { get; set; }
/// <summary>
/// 華氏
/// </summary>
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
/// <summary>
/// Summary
/// </summary>
public string? Summary { get; set; }
}
列舉值狀態碼
/// <summary>
/// 狀態碼
/// </summary>
public enum Code
{
/// <summary>
/// 成功
/// </summary>
Success= 0,
/// <summary>
/// 失敗
/// </summary>
Fail = 9999
}
建立的範例Class
public class PostResponseExample : IExamplesProvider<PostResponse>
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public PostResponse GetExamples()
{
return new PostResponse() { Code = Code.Success, Msg = "成功" , Data = new WeatherForecast()
{
Date = DateTime.Today,
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
} };
}
}
在Post Function上增加需要使用的Attribute,並在Post參數帶入中使用FromHeader(Name ="Token")
/// <summary>
/// 取得預報
/// </summary>
/// <returns></returns>
[HttpPost]
[SwaggerResponse(200, "成功", typeof(PostResponse))]
[SwaggerResponseExample(200, typeof(PostResponseExample))]
public IActionResult Post([FromHeader(Name ="Token")] string token)
{
return Ok(new PostResponse()
{
Code = Code.Success,
Msg = "成功",
Data = new WeatherForecast()
{
Date = DateTime.Now,
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}
});
}
建立EnumTypesSchemaFilter
public class EnumTypesSchemaFilter : ISchemaFilter
{
private readonly XDocument? _xmlComments;
/// <summary>
/// EnumTypesSchemaFilter 建構式
/// </summary>
/// <param name="xmlPath"></param>
public EnumTypesSchemaFilter(string xmlPath)
{
if (File.Exists(xmlPath))
{
_xmlComments = XDocument.Load(xmlPath);
}
}
/// <summary>
/// Apply
/// </summary>
/// <param name="schema"></param>
/// <param name="context"></param>
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (_xmlComments == null) return;
if (schema.Enum != null && schema.Enum.Count > 0 &&
context.Type != null && context.Type.IsEnum)
{
schema.Description += "<p>Members:</p><ul>";
var fullTypeName = context.Type.FullName;
foreach (var enumMember in schema.Enum.OfType<OpenApiInteger>().
Select(v => v.Value))
{
var fullEnumMemberName = $"F:{fullTypeName}.{Enum.ToObject(Type.GetType(fullTypeName!)!, enumMember)}";
var enumMemberComments = _xmlComments.Descendants("member")
.FirstOrDefault(m => m.Attribute("name")!.Value.Equals
(fullEnumMemberName, StringComparison.OrdinalIgnoreCase));
if (enumMemberComments == null) continue;
var summary = enumMemberComments.Descendants("summary").FirstOrDefault();
if (summary == null) continue;
schema.Description += $"<li><i>{enumMember}</i> : {summary.Value.Trim()}</li>";
}
schema.Description += "</ul>";
}
}
}
Program中增加Example與EumType處理
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
options.ExampleFilters();
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath, true);
options.SchemaFilter<EnumTypesSchemaFilter>(xmlPath);
});
//搭配ExampleFilters使用
builder.Services.AddSwaggerExamplesFromAssemblies(Assembly.GetEntryAssembly());
介面上多出了有使用到的Schema
打開Post後可以看到Header多出Token參數帶入欄位
打開PostResponse可以看到回傳的欄位格式以及描述
Responses中多出了預設的範例碼
結論
每次的Post成功接收後,則統一回傳Http StatusCode 200 並配合Json中的自定義識別碼,來決定該次串接的Response結果
而在Header中帶入的Token也可判別授權API的運用,如此便完成進階的使用
資料來源參考