📚

.NET CoreでAPIを構築し、PostgreSQLをデータベースとして使用する方法

2024/06/04に公開

イントロダクション

この記事では、.NET CoreとPostgreSQLを使用してAPIを開発する方法について説明します。APIの開発には、DapperというORMツールを使用します。

Dapperは、シンプルで高速な.NETオブジェクトマッパーであり、SQLクエリの実行と結果のマッピングを容易に行うことができます。そのため、データベースとの対話を効率的に行うための強力なツールとして利用されています。

この記事では、.NET Coreのフレームワークを使用してAPIを構築し、PostgreSQLデータベースとの通信を行う方法に焦点を当てます。

開発環境

オペレーティングシステム: Windows 11 Home
開発ツール: Visual Studio 2022
データベース: PostgreSQL 16.3 (SQL Server 2022)
https://www.postgresql.org/

作成物の概要

ユーザー管理 API

このAPIは、ユーザーの作成、取得、更新、削除などの基本的な操作を提供します。

エンドポイント

  • GET /api/users
    • 全てのユーザーを取得します。
  • GET /api/users/{id}
    • 指定したIDのユーザーを取得します。
  • POST /api/users
    • 新しいユーザーを追加します。
  • DELETE /api/users/{id}
    • 指定したIDのユーザーを削除します。
  • PUT /api/users/{id}
    • 指定したIDのユーザー情報を更新します。

データモデル

ユーザーは以下のプロパティを持ちます。

  • Id (int): ユーザーの一意の識別子。
  • Name (string): ユーザーの名前。
  • Email (string): ユーザーのメールアドレス。
  • Age (int): ユーザーの年齢。

使用方法

  1. APIエンドポイントにリクエストを送信します。
  2. レスポンスを受け取ります。
  3. 必要に応じてレスポンスを処理します。

使用例

全てのユーザーを取得する

GET /api/users/1

指定したIDのユーザーを取得する

GET /api/users/1

新しいユーザーを追加する

POST /api/users
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john@example.com",
  "age": 30
}

指定したIDのユーザーを削除する

DELETE /api/users/1

指定したIDのユーザー情報を更新する

PUT /api/users/1
Content-Type: application/json

{
  "name": "Updated Name"
}

API作成

新しいプロジェクトの作成

フォルダ構成

Program.cs

using System.Data; // System.Data 名前空間を使用するための using ディレクティブ
using Microsoft.Data.SqlClient; // Microsoft.Data.SqlClient 名前空間を使用するための using ディレクティブ
using Npgsql;

internal class Program // プログラムのエントリーポイントを定義する Program クラス
{
    private static void Main(string[] args) // アプリケーションのエントリーポイントである Main メソッド
    {
        var builder = WebApplication.CreateBuilder(args); // WebApplication のビルダーを作成

        // コンテナにサービスを追加する
        // Swagger/OpenAPI の設定については https://aka.ms/aspnetcore/swashbuckle を参照
        builder.Services.AddEndpointsApiExplorer(); // エンドポイントの API Explorer を追加
        builder.Services.AddSwaggerGen(); // SwaggerGen を追加

        builder.Services.AddControllers(); // コントローラーを追加

        // IDbConnection の実装を登録
        // PostgreSQLに接続
         builder.Services.AddScoped<IDbConnection>((sp) =>
        new NpgsqlConnection(builder.Configuration.GetConnectionString("DefaultConnection")));
        
        //SQLserverに接続
        //builder.Services.AddScoped<IDbConnection>((sp) =>
        //new SqlConnection(builder.Configuration.GetConnectionString("DefaultConnection")));

        var app = builder.Build(); // アプリケーションのビルド

        // HTTP リクエスト パイプラインを構成
        if (app.Environment.IsDevelopment()) // 開発環境の場合
        {
            app.UseSwagger(); // Swagger を使用
            app.UseSwaggerUI(); // Swagger UI を使用
            app.UseDeveloperExceptionPage(); // 開発時の例外ページを使用
        }

        app.UseHttpsRedirection(); // HTTPS リダイレクションを使用
        app.UseRouting(); // ルーティングを使用

        // エンドポイントをマッピング
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers(); // コントローラーをエンドポイントにマッピング
        });

        app.Run(); // アプリケーションを実行
    }
}

User.cs

namespace UserAPI.Models
{
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public int Age { get; set; }
    }
}

UsersController.cs

using Microsoft.AspNetCore.Mvc;
using System.Data;
using Dapper;
using UserAPI.Models;

namespace UserAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UsersController : ControllerBase
    {
        private readonly IDbConnection _connection;

        // IDbConnectionの実装を注入するコンストラクター
        public UsersController(IDbConnection connection)
        {
            _connection = connection;
        }

        // 全てのユーザーを取得するエンドポイント
        [HttpGet]
        public async Task<IActionResult> GetAllUsers()
        {
            // データベースから全てのユーザーを非同期に取得
            var users = await _connection.QueryAsync<User>("SELECT * FROM users");
            return Ok(users);
        }

        // 指定IDのユーザーを取得するエンドポイント
        [HttpGet("{id}")]
        public async Task<IActionResult> GetUserById(int id)
        {
            // 指定IDのユーザーを非同期に取得
            var user = await _connection.QueryFirstOrDefaultAsync<User>("SELECT * FROM users WHERE id = @Id", new { Id = id });
            // ユーザーが存在しない場合は404を返す
            if (user == null)
                return NotFound();
            return Ok(user);
        }

        // 新規ユーザーを追加するエンドポイント
        [HttpPost]
        public async Task<IActionResult> AddUser(User user)
        {
            // メールアドレスが既に存在するか確認
            var existingUser = await _connection.QueryFirstOrDefaultAsync<User>("SELECT * FROM users WHERE email = @Email", new { Email = user.Email });
            if (existingUser != null)
                return Conflict("すでにユーザーが存在しています");

            // ユーザーを追加
            await _connection.ExecuteAsync("INSERT INTO users(name, email, age) VALUES(@Name, @Email, @Age)", user);
            // 追加されたユーザーの情報と成功メッセージを返す
            return CreatedAtAction(nameof(GetUserById), new { id = user.Id }, "ユーザー作成に成功しました");
        }

        // 指定IDのユーザーを削除するエンドポイント
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteUser(int id)
        {
            // 指定IDのユーザーを非同期に取得
            var user = await _connection.QueryFirstOrDefaultAsync<User>("SELECT * FROM users WHERE id = @Id", new { Id = id });
            // ユーザーが存在しない場合は404を返す
            if (user == null)
                return NotFound("ユーザーが存在しません");

            // ユーザーを削除
            await _connection.ExecuteAsync("DELETE FROM users WHERE id = @Id", new { Id = id });
            // 削除成功のメッセージを返す
            return Ok("削除に成功しました");
        }

        // 指定IDのユーザー情報を更新するエンドポイント
        [HttpPut("{id}")]
        public async Task<IActionResult> UpdateUser(int id, User user)
        {
            // 指定IDのユーザーを非同期に取得
            var existingUser = await _connection.QueryFirstOrDefaultAsync<User>("SELECT * FROM users WHERE id = @Id", new { Id = id });
            // ユーザーが存在しない場合は404を返す
            if (existingUser == null)
                return NotFound("ユーザーが存在しません");

            // 指定IDのユーザーの名前を更新
            await _connection.ExecuteAsync("UPDATE users SET name = @Name WHERE id = @Id", new { user.Name, Id = id });
            // 更新成功のメッセージを返す
            return Ok("更新に成功しました");
        }
    }
}

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    //SQLserver 接続文字列
    //"DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=test;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
    
    //PostgreSQL 接続文字列
    "DefaultConnection": "Host=localhost;Port=5432;Username=postgres;Password=YOUR_PASSWORD;Database=test"
  }
}

PostgreSQLで上記のUserテーブルを作成する

CREATE TABLE Users (
    Id SERIAL PRIMARY KEY,
    Name VARCHAR(255) NOT NULL,
    Email VARCHAR(255) NOT NULL UNIQUE,
    Age INT NOT NULL
);

Id SERIAL PRIMARY KEY: Id列は自動インクリメントされる整数で、主キーとして設定されています。
Name VARCHAR(255) NOT NULL: Name列は最大255文字の文字列で、NULL値は許可されません。
Email VARCHAR(255) NOT NULL UNIQUE: Email列は最大255文字の文字列で、NULL値は許可されず、ユニーク制約が付けられています。
Age INT NOT NULL: Age列は整数で、NULL値は許可されません。

Usersテーブルに新しいユーザーを追加する

INSERT INTO Users (Name, Email, Age) VALUES ('John Doe', 'john@example.com', 30);

実行結果

Try it outを押下

Executeを押下

成功

Discussion