Laravel 6 系でCRUDができるAPIサーバーを作成
概要
Laravel 6 系(PHP 7.3 系)で Web API サーバを作成します。
phpenv で php をインストール済みと docker compose が使える環境であることを仮定します。
php(7.3)のインストール方法は以下の記事を参照してください。
今回作成したソースコードは以下。
実装
project の作成
composer create-project laravel/laravel laravel6-api-sample --prefer-dist "6.*"
cd laravel6-api-sample
DB の準備
プロジェクト直下に docker-composer.yml
を作成します。
version: "3.5"
services:
db:
image: mysql:5.7.34
container_name: db-container
environment:
MYSQL_DATABASE: "laravel"
MYSQL_ROOT_PASSWORD: "password"
TZ: "Asia/Tokyo"
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
expose:
- "3306"
ports:
- "3306:3306"
volumes:
- ./initdb.d:/docker-entrypoint-initdb.d
restart: "always"
.env ファイルをDB_PASSWORD
の部分を書き換えます。
DB_PASSWORD=password
DB サーバのコンテナを立ち上げます。
docker composer up -d
少し待って、以下のコマンドが問題なく終了すれば準備完了です。
mysql -u root -ppassword -D laravel -h 127.0.0.1 --port 3306 -e 'exit'
モデルの作成
以下のコマンドで、今回使用するモデルを作成します。
php artisan make:model Article -m
以下の2つのファイルが生成されます。
マイグレーションファイルは実行時刻によって名前が変わります。
app/Article.php
database/migrations/2021_09_26_013743_create_articles_table.php
また、database/migrations/2021_09_26_013743_create_articles_table.php
を編集します。
そうすることで、articles のカラムに title と body を追加します。
// database/migrations/2021_09_26_013743_create_articles_table.php
// 中略
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title'); // 追加
$table->text('body'); // 追加
$table->timestamps();
});
}
// 略
編集後、php artisan migrate
によって、更新をします。
$ php artisan migrate
Migration table created successfully.
API のコントローラを作成
API 用のコントローラを作成します。
--api
によって、API 用のコントローラ(ビュー用でない)に不要な処理をあらかじめ削除して生成してくれます。
php artisan make:controller Api/ArticleController --api
以下のファイルが生成されます。
app/Http/Controllers/Api/ArticleController.php
ダミーデータを作成
Article のダミーデータを作成します。
$ php artisan make:seeder ArticlesTableSeeder
Seeder created successfully.
database/seeds/ArticlesTableSeeder.php
という名前のダミーデータ用のファイルが作成されるので、編集します。
<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB; // 追記
// 中略
public function run()
{
// 以下追記
DB::table('articles')->insert([
[
'title' => 'タイトル1',
'body' => '内容1'
],
[
'title' => 'タイトル2',
'body' => '内容2'
],
[
'title' => 'タイトル3',
'body' => '内容3'
],
]);
}
// 略
また、database/seeds/DatabaseSeeder.php
を編集します。
// database/seeds/DatabaseSeeder.php
// 略
public function run()
{
// $this->call(UsersTableSeeder::class);
$this->call(ArticlesTableSeeder::class); // 追記
}
// 略
編集が完了したら、以下のコマンドで挿入します。
$ php artisan db:seed
Seeding: ArticlesTableSeeder
Seeded: ArticlesTableSeeder (0.11 seconds)
Database seeding completed successfully.
実際に挿入されたか確認します。
$ mysql -u root -ppassword -D laravel -h 127.0.0.1 --port 3306 -e 'SELECT * FROM articles;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+---------------+---------+------------+------------+
| id | title | body | created_at | updated_at |
+----+---------------+---------+------------+------------+
| 1 | タイトル1 | 内容1 | NULL | NULL |
| 2 | タイトル2 | 内容2 | NULL | NULL |
| 3 | タイトル3 | 内容3 | NULL | NULL |
+----+---------------+---------+------------+------------+
CRUD を作成
CURD を実装するには、app/Http/Controllers/Api/ArticleController.php
を編集します。
今回は、トランザクション処理やサービスロジックなどの実装を無視しています。
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Article;
class ArticleController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// READ 全取得
$articles = Article::all();
return response($articles, 200);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
// UPDATE
$article = new Article;
$article->title = $request->input('title');
$article->body = $request->input('body');
$article->save();
return response($article, 201);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
// READ 単一取得
$article = Article::find($id);
return response($article, 200);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
// UPDATE
$article = Article::find($id);
$article->title = $request->input('title');
$article->body = $request->input('body');
$article->save();
return response($article, 200);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
// DELETE
Article::destroy($id);
return response('ok', 200);
}
}
ルーティングを定義
routes/api.php
の最後を以下ように修正しますします。
// routes/api.php
// 中略
Route::group(['middleware' => ['api']], function () {
Route::get('articles', 'Api\ArticleController@index');
Route::get('articles/{id}', 'Api\ArticleController@show');
Route::post('articles', 'Api\ArticleController@store');
Route::patch('articles/{id}', 'Api\ArticleController@update');
Route::delete('articles/{id}', 'Api\ArticleController@destroy');
});
ルーティングが追記されたか、以下のコマンドで確認します。
$ php artisan route:list
+--------+----------+-------------------+------+----------------------------------------------------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+-------------------+------+----------------------------------------------------+--------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/articles | | App\Http\Controllers\Api\ArticleController@index | api |
| | POST | api/articles | | App\Http\Controllers\Api\ArticleController@store | api |
| | GET|HEAD | api/articles/{id} | | App\Http\Controllers\Api\ArticleController@show | api |
| | PATCH | api/articles/{id} | | App\Http\Controllers\Api\ArticleController@update | api |
| | DELETE | api/articles/{id} | | App\Http\Controllers\Api\ArticleController@destroy | api |
| | GET|HEAD | api/user | | Closure | api,auth:api |
+--------+----------+-------------------+------+----------------------------------------------------+--------------+
動作確認
curl コマンドによって、処理ができるか確認していきます。
READ 全取得
コマンド。
curl --location --request GET 'http://127.0.0.1:8000/api/articles'
レスポンス。
[
{
"id": 1,
"title": "タイトル1",
"body": "内容1",
"created_at": null,
"updated_at": null
},
{
"id": 2,
"title": "タイトル2",
"body": "内容2",
"created_at": null,
"updated_at": null
},
{
"id": 3,
"title": "タイトル3",
"body": "内容3",
"created_at": null,
"updated_at": null
}
]
READ 一件取得
コマンド。
curl --location --request GET 'http://127.0.0.1:8000/api/articles/1'
レスポンス。
{
"id": 1,
"title": "タイトル1",
"body": "内容1",
"created_at": null,
"updated_at": null
}
CREATE
コマンド。
curl --location --request POST 'http://127.0.0.1:8000/api/articles' \
--header 'Content-Type: application/json' \
--data-raw '{
"title": "test title",
"body": "test body"
}'
レスポンス。
{
"title": "test title",
"body": "test body",
"updated_at": "2021-09-26 10:53:01",
"created_at": "2021-09-26 10:53:01",
"id": 4
}
UPDATE
コマンド。
curl --location --request PATCH 'http://127.0.0.1:8000/api/articles/4' \
--header 'Content-Type: application/json' \
--data-raw '{
"title": "test title update",
"body": "test body update"
}'
レスポンス。
{
"id": 4,
"title": "test title update",
"body": "test body update",
"created_at": "2021-09-26 10:53:01",
"updated_at": "2021-09-26 10:54:26"
}
DELETE
コマンド。
curl --location --request DELETE 'http://127.0.0.1:8000/api/articles/4' \
--header 'Content-Type: application/json' \
--data-raw ''
レスポンス。
ok
Discussion