はじめに
アプリ制作をしてると、データベースとの連携をするのにAPIが必要になる
そのAPIの作成の仕方を忘備録として残しておく
使用するデータベースの作成
まず先に使用するデータベースのサンプルを作成する
構成は下記画像となる
テーブル名はusersだ
テーブルの作成
CREATE TABLE `users` (
`id` int NOT NULL,
`name` varchar(45) COLLATE utf8mb4_general_ci NOT NULL,
`old` int NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`is_deleted` tinyint NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
サンプルデータを挿入する
INSERT INTO `users` (`id`, `name`, `old`, `created_at`, `updated_at`, `is_deleted`) VALUES
(1, '斎藤さん', 30, '2024-04-07 08:58:29', '2024-04-07 08:58:29', 0),
(2, '轟さん', 33, '2024-04-07 08:58:45', '2024-04-07 08:58:45', 0),
(3, '加藤さん', 21, '2024-04-07 08:59:05', '2024-04-07 08:59:05', 0);
プロジェクトの作成
Visual Studio で新しいプロジェクトとして ASP.NET Core Web API を選択する
ASP.NET Core Web API(native AOT) こちらは、プログラムの実行前にコードをネイティブコードにコンパイルする技術になる
パフォーマンスを向上させたりするが、利用可能なAPIや機能に制限があるので通常のASP.NET Core Web APIを使用する
NuGet から取得
今回は、Dappar と Mysql でデータベースとの連携をする
NuGetパッケージで Dappar と Mysql.Data を取得する
またDapper.Contribも取得しておく
Dapper.ContribはCRUD(Create, Read, Update, Delete)操作を簡単に実装できるメソッドを提供しており、属性を使用してテーブル名や主キーなどを指定することができる
データアクセス層の構築
データベースとの連携するファイルの作成をする
まず DataAccess というフォルダを作成する
その中に IMySQLDataAccess.cs と MySQLDataAccess.cs の2つのファイルを作成する
下記コードとなる
public interface IMySQLDataAccess
{
Task<List<T>> LoadData<T, U>(string sql, U parameters);
Task SaveData<T>(string sql, T parameters);
}
using Dapper;
using MySql.Data.MySqlClient;
using System.Data;
public class MySQLDataAccess : IMySQLDataAccess
{
private readonly string _connectionString;
public MySQLDataAccess(string connectionString)
{
_connectionString = connectionString;
}
public async Task<List<T>> LoadData<T, U>(string sql, U parameters)
{
using (IDbConnection connection = new MySqlConnection(_connectionString))
{
var rows = await connection.QueryAsync<T>(sql, parameters);
return rows.ToList();
}
}
public async Task SaveData<T>(string sql, T parameters)
{
using (IDbConnection connection = new MySqlConnection(_connectionString))
{
await connection.ExecuteAsync(sql, parameters);
}
}
}
接続先データベースを設定する
接続先のデータベース情報はappsettings.jsonに記述する
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Port=3306;database=sampledata;user id=*******;password=************"
},
"AllowedHosts": "*"
}
接続するコードを記述
データベースを利用するためのコードをProgram.csに記述する
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
string connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); // 追加
builder.Services.AddTransient<IMySQLDataAccess>(_ => new MySQLDataAccess(connectionString)); // 追加
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
usersテーブルのクラスの作成
データの連携するためのテーブルに合ったクラスを作成する
プロジェクトに Models というフォルダを作成する
Modelsの中に UsersModel.cs を作成してコードを記述する
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace SampleAPI.Models;
[Dapper.Contrib.Extensions.Table("users")]
public class Users
{
[Dapper.Contrib.Extensions.Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[StringLength(45)]
public string Name { get; set; }
[Required]
public int Old { get; set; }
[Required]
[Column("created_at", TypeName = "datetime")]
public DateTime Created_At { get; set; }
[Required]
[Column("updated_at", TypeName = "datetime")]
public DateTime Updated_At { get; set; }
[Required]
[Column("is_deleted")]
public bool Is_Deleted { get; set; }
}
クラスのプロパティ名は命名規則によりパスカルケースを用いる
そのため、最初の文字は大文字としている
※ キャメルケースというのもある
例:firstName など
コントローラーの作成
実際にAPIにアクセスしてデータを取得するためのコントローラーを作成する
Controllersフォルダ上で右クリックをして、追加を選択
その後、コントローラーを追加する
今回は MVCコントローラー – 空 で UsersController.cs を作成する
まず、ユーザーを取得するコードを書いてみる
using Microsoft.AspNetCore.Mvc;
using SampleAPI.Models;
namespace SampleAPI.Controllers;
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly IMySQLDataAccess _dataAccess;
public UsersController(IMySQLDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
[HttpGet]
public async Task<ActionResult<Users>> GetUsers()
{
string sql = $"SELECT * FROM `users` WHERE 1";
var _users = await _dataAccess.LoadData<Users, dynamic>(sql, new { });
if (_users.Count == 0)
{
return NotFound();
}
return Ok(_users);
}
}
デバッグする
現在のプロジェクトの中身は画像のような状態になっている
それではデバッグしてみよう
デバッグモードでWEB APIプロジェクトを起動すると、Swagger UIが自動的に表示される
SwaggerはAPIの仕様を簡単に確認し、テストするためのツールだ
次のようなページが表示される
- Users
- WeatherForecast
の2つが存在するが、WeatherForecastはプログラム作成時初期に作られるサンプルだ
UsersのGET /api/Usersをクリックすると次の画像のように表示されるはずだ
ここにあるTry it outをクリックして出てきたExecuteを実行してみよう
次の画像のようになるはずだ
Jsonデータでデータが帰ってきてるのがわかる
さらにここに記載されてる Curl と Request URL に注目しよう
今回はプログラムを起動したままの状態でRequest URLに直接ブラウザでアクセスしてみる
URLにアクセスをするとJsonデータが表示されてるのがわかるはずだ
このようにデータにアクセスすることができる
データを操作する 引数
次に引数を使って指定データを取得してみよう
先ほどのUsersController.csに下記を追加する
[HttpGet("{id}")]
public async Task<ActionResult<Users>> GetUsers(int id)
{
string sql = $"SELECT * FROM `users` WHERE id = @Id;";
var pins = await _dataAccess.LoadData<Users, dynamic>(sql, new { Id = id });
if (pins.Count == 0)
{
return NotFound();
}
return Ok(pins);
}
再度プログラムを実行してみよう
/api/Users/{id} という項目ができたのがわかる
idに1を入れてExecuteしてみよう
実行すると次の画像のように id 1 のデータが取得できたのがわかる
Request URLを見るとhttps://localhost:7012/api/Users/1とidを指定してデータを取得している
では、動かしたままの状態で https://localhost:7012/api/Users/2 にブラウザで直接アクセスしてみよう
このように id 2 のデータが取得できる
データを操作する Update
それでは次にアップデートをしてみよう
下記コードを追加する
[HttpPut("update/{id}")]
public async Task<IActionResult> UpdateUser(int id)
{
string sql = $"UPDATE `users` SET is_deleted = 1 WHERE id = @Id;";
await _dataAccess.LoadData<Users, dynamic>(sql, new { Id = id });
return NoContent();
}
今まではHttpGetであったが今回はHttpPutだ
アップデートするときはHttpPutを使用する
それではプログラムを動かしてみよう
このようにオレンジ色でPUTが追加されたはずだ
先ほど同様にidに1を入れてExecuteしてみる
そうすると画像のようになっているはずだ
ここで見てもらいたいのがCodeの部分だ
204になってるのがわかる
これは、サーバーがクライアントのリクエストを正常に処理したが、コンテンツを返す必要がないことを示している
実際にhttps://localhost:7012/api/Users/1にアクセスしてデータを見てみよう
データを見てみるとis_Deleteがfalseからtrueに変わったのがわかる
0から1に変わったということだ
データベースにアクセスしてみると is_deleted の数値が変わっているのを確認できる
データを操作する Insert
次はデータを挿入してみよう
使用するのはHttpPostになる
まず、クラスをそのまま挿入できるようにするためにIMySQLDataAccess.csとMySQLDataAccess.csにコードを追加する
Task InsertEntityAsync<T>(T entity) where T : class;
public async Task InsertEntityAsync<T>(T entity) where T : class
{
using (IDbConnection connection = new MySqlConnection(_connectionString))
{
await connection.InsertAsync(entity);
}
}
そしてAPIコントローラーも追加する
UsersController.csに下記コードを追加する
[HttpPost("regist")]
public async Task<IActionResult> RegistUser([FromBody] Users user)
{
await _dataAccess.InsertEntityAsync(user);
return NoContent();
}
これでUsersクラスを追加することができる
プログラムを動かしてみよう
画像のようにPOSTが増えてるはずだ
開くと次のような画像になる
ではここにデータを入れてみよう
これでExecuteをする
このようにデータが入ったはずだ
データベースを確認してみよう
ほげほげが入ってるのがわかる
これでデータをインサートすることもできるようになった
データを操作する Delete
データを削除するコントローラーを作成する
データをDeleteすることはほとんどないため、ほぼ出番のないコードになる
使用するときは注意が必要だ
[HttpDelete("delete/{id}")]
public async Task<IActionResult> DeleteUser(int id)
{
string sql = $"DELETE FROM `users` WHERE id = @Id;";
await _dataAccess.SaveData(sql, new { Id = id });
return NoContent();
}
このようになってるはずだ
それでは実際にDeleteしてみよう
実際に id に 3 を入れてExecuteする
204のコードが出てきたので処理に問題ないようだ
では、データベースを確認してみよう
id 3 のデータが削除されてるのがわかる
さいごに
Deleteコマンドは何度も言うようにデータを削除するというのはほとんどないため、あまり使うことがないコードとなる
特に悪用されたりすることを考えるとセキュリティも強化しなくてはならなくなる
実装するときは考えて実装しよう
簡易的な用語説明
- パスカルケース : 複数の単語を組み合わせて名前を作る際に、各単語の最初の文字を大文字で始める方法
- キャメルケース : 最初の単語を小文字で始め、その後の各単語の最初の文字を大文字で始める方法
コメント