Web APIで複数のプロパティに対してバリデーションをかけたい
以前のプロジェクトでやったこと。
ASP.NET CoreのWeb APIでデータクラスを受け取った際にValidationをやりたい。そういうケースは当然あり、ASP.NET Coreにも検証機能が備わっています。
ASP.NET Coreに任せると[Required]
属性などを付与したプロパティでValidationをかけることができますが、複数のValidation条件の中で一つNGを検出したらそこで処理が中断されるため、1回のリクエストに対する検証項目が1つだけになってしまう。
マスタの登録画面で保存ボタンを押した際など、1度のリクエストで同時に複数の項目へのValidationを行いたいという状況がありました。
次のことをやっていました。
- 検証用Attributeクラスを作る。
Required、Range、大小比較の小さいほう、大きいほうなどを作りました。 - 検証対象のデータクラスのプロパティに検証用Attributeを付与。
- 自前の抽象クラス Validatable を作り、検証対象のデータクラスはこれを継承させる。
- Validatableクラスは void Validate() メソッドを持ち、呼び出されれば検証用Attributeの付与されたプロパティに対し全チェックを行う。
- チェック結果に1つ以上問題があれば、検証エラーのリストを乗せた自作Validation例外をスロー
- ExceptionFilterを自前で実装し、Validation例外を受けて検証エラーのリストを乗せたエラーレスポンスを作って返す
- Controllerでは受け取ったデータクラスに対し Validate()メソッドを呼び出すことで検証を行う
悪いプラクティスを含んでいる可能性もありますのでご注意(ご指摘ただければ幸いです)。
ソースはそのうち追加するかも。
ASP.NET Core, EF Core, PostgreSQLのテストをGitLab CIで回す
以前別のブログに書いた記事のため フレームワークバージョンが古いことにご注意ください
EF Coreを利用したCIをGitLabで回そうとした際にRDBコンテナとの接続のやり方が分からず嵌りましたが、とりあえずできたので書き残しておきます。より適切なやり方があるかもしれません。 私の環境で、フレームワーク等は以下のバージョンを使いました。
- ASP.NET Core 2.2
- EF Core 2.2: ASP.NET Coreの組み込み
- Npgsql EntityFramework Core 2.2.0
- PostgreSQL 11.1
やりたいこと
- Docker ExecutorによるGitLab CI
- ASP.NET CoreのコンテナとPostgreSQLコンテナを起動
- PostgreSQLに対してEF Coreのマイグレーションを行う
- DBアクセスを含んだテストを実行
やること
- ASP.NET Coreプロジェクトを作成
- EF Coreモデルを作成
- テストを作成
- GitLab CIの設定ファイルを作成
1. ASP.NET Coreプロジェクトを作成
プロジェクト名・ソリューション名はSampleApiとします。 WebApiとしてプロジェクトを作成しますが、本記事の範囲では何でも構いません。 さらにテストプロジェクトSampleTestを追加します。
mkdir SampleApi cd SampleApi dotnet new sln dotnet new webapi -o SampleApi dotnet new xunit -o SampleTest dotnet sln add SampleApi SampleTest
作成できるプロジェクトはインストールされたSDKバージョンに依存します。
2. EF Coreのモデルを作成
適当なモデルをSampleApiプロジェクトに追加します。
public class User { [Key] public long Id { get; set; } public string Name { get; set; } }
上のモデルを含むDbContextを作成します。 接続文字列を環境変数から拾うようにしています。
public class SampleDbContext : DbContext { public DbSet<User> Users { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING"); optionsBuilder.UseNpgsql(connectionString); } }
NugetでNpgsql.EntityFramework.Coreを取得する必要があります。
3.テストの作成
テストプロジェクトにテストを追加します。 今回はEF Coreを使いデータを突っ込んで取り出すだけのテストです。
public class UnitTest1 { [Fact] public void Test1() { //arrange var sut = new SampleDbContext(); var id = 1; var user = new User() {Id = id, Name = "Alice"}; //act sut.Users.Add(user); sut.SaveChanges(); var result = sut.Users.First(u => u.Id == id); //assertion Assert.Equal(user.Id, result.Id); Assert.Equal(user.Name, result.Name); } }
4. GitLab CIの設定ファイルを作成
GitLab CIを動かすために .gitlab-ci.yml を追加します。
PostgreSQLコンテナの設定はGitLab公式のUsing PostgreSQLを参考にしました。
DB_CONNECTION_STRING
は上のSampleDbContextで使う環境変数で、PostgreSQLコンテナの設定に合わせます。
stages: - test test: stage: test image: microsoft/dotnet:2.2-sdk services: - postgres:11.1 variables: POSTGRES_DB: nice_marmot POSTGRES_USER: runner POSTGRES_PASSWORD: "admin1234" DB_CONNECTION_STRING: "Host=postgres;Username=runner;Password=admin1234" script: - cd SampleApi - dotnet restore - cd SampleApi - dotnet ef migrations add InitialCreate - dotnet ef database update - cd .. - dotnet test
以上をpushするとパイプラインが走り、マイグレーション、テストまで動いてくれました。
Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Raspberry pi クラスタ上でAmbassador Patternを動かそうとしてはまる
コンテナの利用パターンを学ぶために 分散システムデザインパターン を読んでいます。
www.oreilly.co.jp
3章アンバサダーパターンより。
シャードしたRedisキャッシュに対するプロキシとして twemproxyをアプリケーションコンテナのPodに配置する設定が出てきますが、私の環境では正常に動作しませんでした。
$ kubectl logs ambassador-example twemproxy standard_init_linux.go:211: exec user process caused "exec format error"
結論から言うと、RaspberryPiはarmアーキテクチャのため使用しているイメージが動かなかったようでした。
https://hub.docker.com/r/ganomede/twemproxy/
書籍ではこちらのイメージを利用していますが、ここのDockerfileをそのまま自環境でビルド・プッシュして、プッシュしたイメージを利用すれば解決しました。
プッシュ先はGitLabのコンテナレジストリを使いました。
Raspberry pi 4 によるKubernetesクラスタ [2020/07]
家にあるraspberry pi 4の 3台をもってクラスタを構成しました。
環境構築にあたっては、こちらを参考にさせていただきました。
Raspberry PiでおうちKubernetes構築【物理編】
Raspberry PiでおうちKubernetes構築【論理編】
基本的に記事の通り。
raspberrypi でswapfileを使わない設定をするために
sudo dphys-swapfile swapoff
をやった後で、再起動後に設定が消えてる気がするので
sudo systemctl disable dphys-swapfile
をやった。