C# で Web API を作って呼ぶ
今日はゆる~く以下の記事を .NET 6 でやっていこうと思います。
今回は、元記事にあるとおり HttpClient クラスを使った方法で行こうと思います。
swagger.json からクライアントを生成したりといった方法もありますが、HttpClient を使った方法がとりあえず一番つぶしが効く方法であるのでやり方を知っておいて損はないです。
Web API から作ってみよう
元記事では Web API は存在するものとしてやってますが、今回は Web API を作るところからやろうと思います。
Visual Studio 2022 で ASP.NET Core (空) のプロジェクトを作ります。
これは一番少ないコード量で Web API が作れる Minimal API と呼ばれるタイプのプロジェクトになります。
とりあえず question プロパティを持つ以下の JSON を POST で受け取りつつ apiKey をクエリパラメーターで受け取る感じですね。そして固定のレスポンスを返す感じです。
リクエスト
項目 | 値 |
---|---|
URL | https://api.example.com?apiKey=hogehoge |
Method | POST |
Content Type | application/json |
Request Body | {"question": "ちょうしはどう?"} |
レスポンス
項目 | 値 |
---|---|
Response body | { "answer" : "(´・ω・`)" } |
ソースコード
ではサーバーサイドのコードを書いてみましょう。といっても大した量のコードではないので全体を載せます。
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// / に対して POST が来たら呼ばれる処理を登録
app.MapPost("/", (
// body からのパラメーター
RequestBody body,
// クエリパラメータから受け取る
string? apiKey,
// ロガー
ILogger<Program> logger) =>
{
// apiKey が hogehoge じゃない場合は NG
if (apiKey != "hogehoge") return Results.Unauthorized();
// 一応受けた質問はログに出しておく
logger.LogInformation("{question}", body.Question);
// 結果を返す
return Results.Ok(new Response { Answer = "(´・ω・`)" });
});
app.Run();
// リクエストとレスポンス
class RequestBody
{
public string? Question { get; set; }
}
class Response
{
public string? Answer { get; set; }
}
リクエストのボディやクエリパラメーターがいい感じに引数に代入されるので楽でいいですね。自分で JSON をパースしなくていいので。
このコードを実行すると起動しているポート番号がわかるので例えば 7037 番ポートで https で待ち受けている場合は以下のようなリクエストを送ることで動作を確認することが出来ます。
POST https://localhost:7037/?apiKey=hogehoge
Content-Type: application/json
{ "question": "ちょうしはどう?" }
レスポンスは固定なので省略します。apiKey が hogehoge 以外の場合は 401 Unauthorized が返されます。また実行時に表示されているコンソールにちょうしはどう?
のように JSON の question に設定した値が表示されるのが確認できます。
これで API が出来ました。ではこれを呼んでみましょう。
Web API を呼んでみよう
では呼んでみましょう。コンソールアプリのプロジェクトを Visual Studio 2022 で作ってコードを書いていきます。
using System.Net.Http.Json;
// Web API を呼ぶための HttpClient を作る
var client = new HttpClient();
// POST メソッドで JSON の Body のリクエストを投げる
var response = await client.PostAsJsonAsync(
"https://localhost:7037/?apiKey=hogehoge",
new RequestBody { Question = "ちょうしはどう?" });
// レスポンスのステータスコードが成功していたら Answer の値を出力
if(response.IsSuccessStatusCode)
{
var responseBody = await response.Content.ReadFromJsonAsync<Response>();
Console.WriteLine(responseBody?.Answer);
}
// リクエストとレスポンス
class RequestBody
{
public string? Question { get; set; }
}
class Response
{
public string? Answer { get; set; }
}
とりあえず、よくあるパターンの JSON でのやり取りを行うケースに特価した PostAsJsonAsync
というメソッドや ReadFromJsonAsync
というメソッドがあるので非常にすっきりと書けます。リクエストとレスポンスのボディの値に対応するクラスはサーバーサイドとコードを共有できます。
今回はコピペで共有していますが、本来であればクラスライブラリプロジェクトなどで共通化しておくと良いでしょう。
OpenAPI/Swagger 使いたい
ここらへんのドキュメントを見ながらやっていきます。
Web API 側
Swagger を使う場合には、Web API のプロジェクトに以下のパッケージを NuGet で追加します。
- Swashbuckle.AspNetCore
- Swashbuckle.AspNetCore.Annotations
そして先ほどのコードに Swashbuckle 関連の属性や下準備のコードを追加します。
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
var builder = WebApplication.CreateBuilder(args);
// Swagger を使う下準備
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
// デバッグ実行時のみ swagger.json と swagger ui を有効化
app.UseSwagger();
app.UseSwaggerUI();
}
// / に対して POST が来たら呼ばれる処理を登録
app.MapPost("/",
// 200 OK の時のレスポンスボディは Response クラスであることを指定
[SwaggerResponse(200, type: typeof(Response))]
(
// body からのパラメーター
RequestBody body,
// クエリパラメータから受け取る
string? apiKey,
// ロガー
ILogger<Program> logger
) =>
{
// apiKey が hogehoge じゃない場合は NG
if (apiKey != "hogehoge") return Results.Unauthorized();
// 一応受けた質問はログに出しておく
logger.LogInformation("{question}", body.Question);
// 結果を返す
return Results.Ok(new Response { Answer = "(´・ω・`)" });
}).WithName("MyApi");
app.Run();
// リクエストとレスポンス
class RequestBody
{
public string? Question { get; set; }
}
class Response
{
public string? Answer { get; set; }
}
この状態で実行して https://localhost:ポート番号/swagger/v1/swagger.json
にアクセスすると以下のような JSON が返ってきます。よさそうですね。
{
"openapi": "3.0.1",
"info": {
"title": "MyRestApi",
"version": "1.0"
},
"paths": {
"/": {
"post": {
"tags": [
"MyRestApi"
],
"operationId": "MyApi",
"parameters": [
{
"name": "apiKey",
"in": "query",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestBody"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Response"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"RequestBody": {
"type": "object",
"properties": {
"question": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"Response": {
"type": "object",
"properties": {
"answer": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
}
}
}
}
Web API を呼ぶ側
Visual Studio 2022 ではプロジェクトの右クリックメニューから追加→サービス参照の追加を選ぶと以下のように OpenAPI を追加する画面が出てきます。
VS Code などの CLI を使う場合には以下の OpenAPI ツールを使うことで同じようなことが出来ると思います。(使ったことはないですが…)
以下のように項目を埋めて完成を押すとクライアントのコードが生成されます。
生成されたコードを使って Web API を呼ぶコードは以下のようになります。
タイプセーフでいいですね。
using CallRestApi.OpenAPIs;
var client = new ApiClient(
"https://localhost:7037",
new HttpClient());
var response = await client.MyApiAsync("hogehoge", new() { Question = "ちょうしはどう?" });
Console.WriteLine(response.Answer);
まとめ
ということで Web API を作って呼ぶということをやってみました。結構サクッと書けるのと OpenAPI/Swagger も対応していたりするので用途に応じて使い分けるといいと思います。
今回はコンソールアプリからサクッと API をたたくだけだったので気にしていませんが、1プロセスで複数回 Web API をたたいたり、Web アプリからさらに Web API をたたくようなケースでは HttpClient
は自分で new
を行わずに以下のページにある IHttpClientFactory
を使うようにしましょう。
Discussion