🔷

もう技術選定や設計に悩まない!?全部入りフルスタックTypeScriptフレームワークAdonisJS - マイグレーション&モデル編

2025/02/27に公開

前回の記事では、AdonisJS v6のインストール方法やルーティング、コントローラの基礎について解説しました。
今回は、データベース操作の基盤となるマイグレーションとモデルについて詳しく見ていきます。

1. Lucid ORMとは?

AdonisJSには、データベース操作を効率的に行うためのORM(Object-Relational Mapping)であるLucidが組み込まれています。Lucidは、Knexをベースに構築されたSQLクエリビルダーであり、Active Recordパターンに準拠したクラスベースのモデルを提供します。これにより、データベースとのやり取りを直感的かつ強力に行うことが可能です。

https://lucid.adonisjs.com/

https://adonisjs-docs-ja.vercel.app/guides/database/lucid

2. マイグレーションの作成

マイグレーションは、データベースのスキーマ(構造)をバージョン管理し、変更を追跡するための仕組みです。新しいテーブルの作成や既存テーブルの変更をコードベースで管理できます。

https://lucid.adonisjs.com/docs/migrations

マイグレーションファイルの作成

新しいマイグレーションを作成するには、以下のコマンドを実行します。

node ace make:migration post

このコマンドにより、database/migrations/ディレクトリ内にタイムスタンプ付きのマイグレーションファイルが生成されます。ファイル名はYYYYMMDDHHMMSS_create_posts_table.tsのようになります。

マイグレーションファイルの編集

生成されたマイグレーションファイルを開き、upメソッド内にテーブル作成のロジックを記述します。

import { BaseSchema } from '@adonisjs/lucid/schema';

export default class extends BaseSchema {
  protected tableName = 'posts';

  async up() {
    this.schema.createTable(this.tableName, (table) => {
      table.increments('id');
      table.string('title').notNullable();
      table.text('content').notNullable();
      table.timestamp('created_at')
      table.timestamp('updated_at')
    });
  }

  async down() {
    this.schema.dropTable(this.tableName);
  }
}

マイグレーションの実行

マイグレーションをデータベースに適用するには、以下のコマンドを実行します。

node ace migration:run

これにより、upメソッドの内容が実行され、データベースに変更が反映されます。

3. モデルの作成

モデルは、データベースのテーブルと対応するクラスであり、データの取得や保存などの操作を行います。Lucidでは、モデルを使用してデータベースとのやり取りを簡潔に記述できます。

https://lucid.adonisjs.com/docs/models

モデルファイルの作成

新しいモデルを作成するには、以下のコマンドを実行します。

node ace make:model post

このコマンドにより、app/models/ディレクトリ内にpost.tsというファイルが生成されます。

モデルクラスの定義

import { DateTime } from 'luxon';
import { BaseModel, column } from '@adonisjs/lucid/orm';

export default class Post extends BaseModel {
  @column({ isPrimary: true })
  declare id: number

  @column()
  declare title: string

  @column()
  declare content: string
  
  @column.dateTime({ autoCreate: true })
  declare createdAt: DateTime

  @column.dateTime({ autoCreate: true, autoUpdate: true })
  declare updatedAt: DateTime
}

4. コントローラーの作成とDB操作

コントローラーファイルの作成

以下のコマンドを実行し、posts_controllerを作成します。

node ace make:controller posts_controller

これにより、app/controllers/posts_controller.tsが生成されます。

コントローラーでのDB操作

作成されたposts_controller.tsを編集し、以下のようにデータベース操作を実装します。

import type { HttpContext } from '@adonisjs/core/http'
import Post from '#models/post'

export default class PostsController {
  async index({ response }: HttpContext) {
    const posts = await Post.all()
    return response.json(posts)
  }

  async store({ request, response }: HttpContext) {
    const data = request.only(['title', 'content'])
    const post = await Post.create(data)
    return response.json(post)
  }

  async show({ params, response }: HttpContext) {
    const post = await Post.find(params.id)
    return response.json(post)
  }

  async update({ params, request, response }: HttpContext) {
    const post = await Post.find(params.id)
    if (post) {
      post.merge(request.only(['title', 'content']))
      await post.save()
    }
    return response.json(post)
  }

  async destroy({ params, response }: HttpContext) {
    const post = await Post.find(params.id)
    if (post) {
      await post.delete()
    }
    return response.json({ message: 'Deleted successfully' })
  }
}

ルーティングの設定

コントローラをルーティングに追加するため、start/routes.tsを編集します。

import router from '@adonisjs/core/services/router'
const PostsController = () => import('#controllers/posts_controller')

router.get('/posts', [PostsController, 'index'])
router.post('/posts', [PostsController, 'store'])
router.get('/posts/:id', [PostsController, 'show'])
router.put('/posts/:id', [PostsController, 'update'])
router.delete('/posts/:id', [PostsController, 'destroy'])

// 前記事のルーティングは削除
// router.get('/posts/:id', ({ params }) => {
//   return `この投稿のIDは${params.id}です。`
// })

router.resource()を使用した省略記法

AdonisJSでは、CRUDルートを簡潔に定義するために router.resource() を使用できます。

router.resource('posts', PostsController).apiOnly();

この記法を使うと、以下のルートが自動的に定義されます。

メソッド ルート コントローラメソッド
GET /posts index
POST /posts store
GET /posts/:id show
PUT /posts/:id update
DELETE /posts/:id destroy

https://adonisjs-docs-ja.vercel.app/guides/basics/controllers#api専用ルートの登録

5. CSRFの無効化

AdonisJSでは、デフォルトでCSRF保護が有効になっています。そのため、APIの動作確認を行う際にCSRFエラーが発生する可能性があります。

CSRF保護を無効化するには、config/shield.ts を編集し、以下のように設定を変更します。

import { defineConfig } from '@adonisjs/shield'

const shieldConfig = defineConfig({
  // 省略...

  /**
   * Configure CSRF protection options. Refer documentation
   * to learn more
   */
  csrf: {
    enabled: false, // <- 変更する
    exceptRoutes: [],
    enableXsrfCookie: true,
    methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
  },

  // 省略...
}

export default shieldConfig

https://adonisjs-docs-ja.vercel.app/guides/security/securing-ssr-applications#設定リファレンス

6. APIの動作確認

以下は、それぞれのリクエスト処理を動作確認するための curl コマンドです。

index メソッド

curl -X GET http://localhost:3333/posts

store メソッド

curl -X POST http://localhost:3333/posts \
  -H "Content-Type: application/json" \
  -d '{"title": "New Post", "content": "This is the content of the new post"}'

show メソッド

curl -X GET http://localhost:3333/posts/1

update メソッド

curl -X PUT http://localhost:3333/posts/1 \
  -H "Content-Type: application/json" \
  -d '{"title": "Updated Title", "content": "Updated content"}'

destroy メソッド

curl -X DELETE http://localhost:3333/posts/1

これらのコマンドを使用して、それぞれのエンドポイントが正しく動作するか確認できます。

6. まとめ

この記事では、AdonisJS v6のLucid ORMを使用したデータベースの操作方法について解説しました。
次回の記事では、バリデーションについて詳しく解説します!

Fusic 技術ブログ

Discussion