Nuxt 3 Beta から Laravel 8 で構築したAPIを叩いてみる
はじめに
趣味と(業務で使用することになるLaravel + Nuxt構成の)キャッチアップもかねてLaravel + Nuxt構成の個人開発を始めています。
どうせなら「なるべく新しいものを使用したい!」との考えからそれぞれの現状の最新メジャーバージョンであるLaravel8 + Nuxt3(Vue3)の構成でアプリケーションを構築することにいたしました。(ただNuxt3は現時点でBetaであり、案件での採用は全くもって現実的とは言えないようです。先んじてキャッチアップしておくことで来るべき本採用に備えようという魂胆です。)
今回の目的
Dockerを使用してLaravel8のAPIサーバーコンテナとNuxt3のフロントコンテナを用意して、nginxでそれぞれをリバースプロキシさせます。その上でNuxt側からLaravelのAPIを叩く処理までやっていきます。
注意事項
この記事から学べること・学べないこと
-
学べること
- nuxt3 + Laravel8環境のセットアップ
- Laravel8で作成したAPIをnuxt3から実行する方法
- 上記の環境をDockerを用いて構築する
- nginxを用いたリバースプロキシの設定
-
学べないこと
- nuxtやLaravelなどの各技術の基礎知識
- 各技術の新しいバージョンに関する詳細情報
- Docker以外の開発環境のセットアップ
- フロントとサーバーを分離しない構成
使用技術
技術名 | バージョン | この記事での用途 |
---|---|---|
Node | 17.5.0 | Nuxt用のコンテナに使用されるNode.js |
Nuxt | 3.0.0 | フロント用のフレームワーク(APIサーバーとは分離想定) |
Vue | 3.2.31 | Javascriptライブラリ |
Laravel | 8.80.0 | APIサーバー |
Docker | 20.10.12 | ローカル開発環境の構築 |
Nginx | 1.20.2 | フロント・サーバーそれぞれのリバースプロキシ |
実際のアプリケーションは上記の他にもデータベースなどありますが、本記事の趣旨と反するため割愛させていただきます。
実際にやっていきます
ディレクトリ構成
最終的には以下のようなディレクトリ構成になります。
- sample
- frontend # フロントエンドリソース
- backend # バックエンドリソース
- docker
- front
Dockerfile
- php
Dockerfile
php.ini
- php-fpm.d
zzz-www.conf
- nginx
Dockerfile
default.conf
docker-compose.yml
docker-composeファイルの作成
sampleディレクトリの中にdocker-compose.ymlを作成します。
version: "3.9"
volumes:
php-fpm-socket:
psysh-store:
services:
app:
build:
context: .
dockerfile: ./docker/php/Dockerfile
container_name: sample_app
volumes:
- type: volume
source: php-fpm-socket
target: /var/run/php-fpm
volume:
nocopy: true
- type: bind
source: ./backend
target: /work/backend
- type: volume
source: psysh-store
target: /root/.config/psysh
volume:
nocopy: true
web:
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
container_name: sample_nginx
ports:
- ${WEB_PORT}:80
- "9000:9000"
volumes:
- type: volume
source: php-fpm-socket
target: /var/run/php-fpm
volume:
nocopy: true
- type: bind
source: ./backend
target: /work/backend
front:
build:
context: .
dockerfile: ./docker/front/Dockerfile
container_name: sample_front
volumes:
- ./frontend:/var/www/nuxt
ports:
- ${FRONT_PORT}:3000
- '24678:24678'
docker-composeのバージョンは3.9
を使用しています。
app
コンテナがLaravel web
コンテナがnginx front
コンテナがnuxtとなります。
container_name
は必ず指定してください。(コンテナ間通信する際にこの名前を使用します。)
ports:
- ${WEB_PORT}:80
- "9000:9000"
上記のようにnginxでポートを2つ指定しているのはフロント、サーバー共にリバースプロキシさせるためです。(80番アクセスでフロント、9000番アクセスでAPI)
PHPコンテナ
Dockerfile
FROM php:8.1-fpm-bullseye
SHELL ["/bin/bash", "-oeux", "pipefail", "-c"]
# timezone environment
ENV TZ=UTC \
# locale
LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
# composer environment
COMPOSER_ALLOW_SUPERUSER=1 \
COMPOSER_HOME=/composer
COPY /usr/bin/composer /usr/bin/composer
RUN apt-get update && \
apt-get -y install git libicu-dev libonig-dev libzip-dev unzip locales && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
locale-gen en_US.UTF-8 && \
localedef -f UTF-8 -i en_US en_US.UTF-8 && \
mkdir /var/run/php-fpm && \
docker-php-ext-install intl pdo_mysql zip bcmath && \
composer config -g process-timeout 3600 && \
composer config -g repos.packagist composer https://packagist.org
COPY ./docker/php/php-fpm.d/zzz-www.conf /usr/local/etc/php-fpm.d/zzz-www.conf
COPY ./docker/php/php.ini /usr/local/etc/php/php.ini
WORKDIR /work/backend
php.iniとzzz-www.confのコードは割愛させていただきます。
nginxコンテナ
Dockerfile
FROM node:16-alpine as node
FROM nginx:1.20-alpine
SHELL ["/bin/ash", "-oeux", "pipefail", "-c"]
ENV TZ=UTC
RUN apk update && \
apk add --update --no-cache --virtual=.build-dependencies g++
# node command
COPY /usr/local/bin /usr/local/bin
# npm command
COPY /usr/local/lib /usr/local/lib
# yarn command
COPY /opt /opt
# nginx config file
COPY ./docker/nginx/*.conf /etc/nginx/conf.d/
WORKDIR /work/backend
default.conf
access_log /dev/stdout main;
error_log /dev/stderr warn;
server {
listen 80;
server_name localhost;
charset utf-8;
location / {
proxy_pass http://host.docker.internal:3000/;
proxy_redirect off;
}
}
server {
listen 9000;
server_name localhost;
root /work/backend/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
リバースプロキシの設定は主にこのファイルで行っています。詳細は割愛しますが、localhost:9000にアクセスするとLaravelが立ち上がるようになっており、localhost:80にアクセスするとlocalhost:3000
にリバースプロキシされるようになっております。
location / {
proxy_pass http://host.docker.internal:3000/;
proxy_redirect off;
}
Nuxtコンテナ
Dockerfile
FROM node:17.5.0-alpine
WORKDIR /var/www/nuxt
RUN apk update && \
apk add git curl
alpineにはgit
もcurl
も入っていないため、追加でインストールしています。
Laravelのインストール
cd sample
mkdir -p backend
docker compose build --no-cache --force-rm
docker compose up -d
docker compose exec app composer create-project --prefer-dist laravel/laravel .
docker compose exec app php artisan key:generate
docker compose exec app php artisan storage:link
docker compose exec app chmod -R 777 storage bootstrap/cache
docker compose exec app php artisan migrate:fresh --seed
Laravelのインストールが完了したらlocalhost:9000にアクセスしてwelcomeページが表示されることを確認します。
Nuxtのインストール
nuxt2までのコマンドと変わっており、質問責めもなくなっています。
docker compose exec front ash
npx nuxi init front # front の部分にはアプリの名前(任意)を入れます
cd front
npm run dev # サーバーの立ち上げ
Nuxtのインストールが完了したらlocalhost:80にアクセスしてwelcomeページが表示されることを確認します。
LaravelでAPIを作成する
corsの設定をします。以下のようにcors.phpを修正し、環境変数から接続を許可するURLを指定します。(今回であればHOST_URL=http://localhost:3000)
...
'allowed_origins' => [env('HOST_URL')],
...
次にAPI用のルーティングを作成します。
Route::get('/check', function (){
return response()->json([
'message'=>'hello world.'
]);
});
以上でLaravel側での作業は完了です。最後にlocalhost:9000/api/checkへアクセスしてjsonが取得できているかを確認します。
NuxtからAPIに接続
nuxtのapp.vueファイルを下記のように書き換えてください。
<template>
<div>
<p>{{data}}</p>
</div>
</template>
<script setup>
const {data} = await useFetch('http://sample_nginx:9000/api/check');
</script>
Nuxt3では新機能(?)としてuseFetch
というものがあり、こちらは主に外部のAPIに接続して非同期処理を行うものだそうです。(蛇足ですがこれとuseAsyncData
はNuxt3の目玉機能のように紹介されていました。)
URLの注意点としてlocalhost
ではないことに注目してください。localhost
にしてしまうとホストのアドレス(127.0.0.1)に接続してしまいます。コンテナのアドレスを名前解決するためにcontainer_name
を指定し、それを使用することでコンテナ間通信を実現します。またlaravelはnginxを噛ませているので、APIアクセス時もLaravelコンテナにアクセスするのではなく、nginxコンテナにアクセスしています。
localhost:80にアクセスしてjsonが取得できていれば、無事完了となります。お疲れ様でした。
おわりに
zennへの初めての投稿となります。
完全に私信ではあるのですが、私自身サーバーサイドエンジニア歴4ヶ月(うち2ヶ月はQA業務に従事していたため実質は2ヶ月です。)という若輩者であり、まだまだエンジニアとして至らない点も多いかと思いますが、今回思い切って筆をとってみました。
目的としては自分用のメモとしての側面も強いですが、このようなフロント・サーバーを分離する構成というのも珍しくはないため、このような知見が活きる場面は実は多いんじゃないか?と思って記事にしようと考えました。
文章を書くということも今までそれほど多くはなかったので、あまり読みやすい記事には仕上がっていないかもしれません。それにもかかわらず最後まで読んでいただけたのであれば感無量です。
お手数ですがもし宜しければ、文章の誤りや知識不足、認識の誤りなどご指摘いただけますと大変助かります。
おまけ
直接的に関係があるわけではありませんが、参考にさせていただいた(これからもおそらく参考にさせていただく)素敵な記事を紹介いたします。
公式Doc
Nuxt 3 を今すぐオススメしたい 15 のポイント
Nust3の新しい機能
Nuxt 3がパブリックベータ版になったので新機能の紹介や所感など
Discussion