LoginSignup
30

More than 5 years have passed since last update.

AWS上で構築するRESTfulアプリ勉強会~Web開発ワークショップ~【第1回】の当日実施内容まとめ

Last updated at Posted at 2015-01-28

勉強会-開発パート - 第1回当日手順

本投稿は、2015/1/23に行われたAWS上で構築するRESTfulアプリ勉強会~Web開発ワークショップ~【第1回】で使用した資料を再構成したものです。

※参加された方へ。
資料に幾つか不備、不十分な点がありましたが、修正したり詳しくしたりしています。当日これぐらい書けていればもう少しスムーズに進んだと思いますが...。スミマセンでした。
この資料を元にもう一回やってみてフィードバックもらえると助かります。
なお、第2回はこの内容を終えていることが前提になりますのでよろしくお願いします。

メニュー

開発用サーバ作成

  1. AWSマネージメントコンソールにログイン
  2. 元にするAMI(マシンイメージ)を検索
  3. インスタンスタイプを選択
  4. インスタンス詳細設定
  5. ストレージ設定
  6. タグ設定
  7. セキュリティグループ設定
  8. 確認画面
  9. キーペア作成
  10. サーバ完成!
  11. ブラウザでアクセスしてみる
  12. SSHでアクセスしてみる

GitHubからソース取得

  1. fork
  2. 開発用サーバにリポジトリをクローン

シンプルTODOアプリ作成

  1. POSTMANの準備
  2. プログラミング
    • そのまえに、urlとController.Actionの関係について(重要)
    • URL
    • 行う処理
    • まとめると
    • HTTPレスポンスコードについて
    • ソース修正手順
    • 開発用ブランチ作成
    • ソースを修正する。
    • POSTMANで動作確認
    • phpMyAdminでデータ確認
    • git初期設定
    • git add, commit
    • git push
    • ソース修正箇所
    • 修正ファイルのdiff
    • 追加ファイル

今回作成する開発用サーバ

OSや基本的なソフトウェアがインストールされたマシンイメージをAWSではAMI(Amazon Machine Image)と呼びます。
今回は、弊社で作成したAMIを元にEC2インスタンスを作成します。
 ※弊社がそのAMIを作成した手順については
AWS上で構築するRESTfulアプリ勉強会~Web開発ワークショップ~【第1回】の事前準備内容まとめ - Qiita
で公開しています。参考にしてください。
 ※こうした方がいいよ、等あればコメントよろしくお願いします!

インストール済みプロダクト

予め下記プロダクトをインストール済みです。
今回の手順で開発環境を作成すればすぐに使用可能となります。

プロダクト バージョン
apache 2.4.10-1.59
php 5.5.20-2.94
mysql 5.6.14-3
phpMyAdmin 4.0.10.7-1
git 2.1.0
xdebug 2.2.3-1

事前に準備しておくもの(必須)

  • awsアカウント
    • 適当にEC2インスタンスが作成できることを確認しておくとベターです。
  • GitHubアカウント
    • 今回はログインさえできれば準備OKです。
  • chromeブラウザ
    • 説明はchromeブラウザをベースにしています。
    • 今後もchromeブラウザをベースに資料、説明を行います。
  • postman

    • 作成したAPIのテストツールchromeブラウザの拡張機能です。
    • 似たようなツールはたくさんありますので、愛用のものがあれば別のそれでもいいですが、資料、説明はPOSTMANベースです。
  • sshコマンドが叩ける環境

    • Macの方は標準のターミナルから実行できるので事前準備は特に必要ないです。
    • Windowsの方は、別途ターミナルソフトウェアをご準備ください。
      • 当資料では、puttyを例にして説明しています。事前にPuTTY Download Pageよりインストールしておいてください(インストーラでインストールしたくない場合はputty.zipをダウンロードしてすきなところに解凍すればOKです。putty以外を愛用していて、linuxサーバへのsshログインが問題なく行える場合は好きなターミナルソフトウェアをご使用ください。
  • Vimまたはemacsの基本操作が出来るようになっておく。

    • サーバにログインして作業することになりますので、エディタはサーバ上のVimまたはemacsを使用します。基本操作は覚えておいてください(ローカルで編集してターミナル上でコピペ出来るレベルで最低限はOKです!)。
    • サーバ上のファイルをローカルPC上のエディタから編集する他の方法もそのうちまとめます...

開発用サーバ作成

では、事前準備済みのAMIから以下の手順でEC2インスタンスを作成します。

1. AWSマネージメントコンソールにログイン

ログイン後、下図のEC2をクリックします。


aws_menu.png


2. 元にするAMI(マシンイメージ)を検索

下記手順で当該のAMIを表示させます。

下記AMIsの部分をクリックします。


aws_sidemenu.png


次に、下記の通り操作します。

リージョンがTokyoになっていることを確認。

画面上部右端にリージョンの表示があります(Tokyoになっている場合)。


ami_region.png


Tokyoになっていない場合、下図のようにTokyoリージョンを選択してください。


ami_region_select.png


AMIを検索します。

  • フィルタを[Public Images]に設定
  • AMI ID ami-644f5165で検索(suzukishoutenで検索しても出てくるはずです)。

ami_search_result.png


見つかったら、選択して[Launch]ボタンをクリック。
ami_launch.png

以降、作成するインスタンスの設定をしていきます。

3.インスタンスタイプを選択

t2.microを選択して[Next]。


ec2_step2.png


4.インスタンス詳細設定

基本はデフォルトで[Next]クリックでOKです。。
Protect against accidental terminationにチェックを入れていますが、ここにチェックしておくと、インスタンス完成後に間違っていterminate(破棄!)をクリックしてしまった時に救われます。(このチェックを外しておかないとterminateできない)
ですので、チェックを入れることをおすすめします。


ec2_step3.png


5.ストレージ設定

ストレージを追加します。デフォルトでOK。[Next]クリック。


ec2_step4.png


6.タグ設定

好きな名前をつけて[Next]クリック。
※スクリーンショットではstudy_01と命名。


ec2_step5.png


7.セキュリティグループ設定

アクセスを許可するプロトコルやポートを設定します。
下記の通り設定し、[Review And Launch]をクリック。

  • Create a new security groupを選択
  • Security group name 好きな名前
  • Description 好きな説明文
  • SSH Anywhere※
  • Http Anywhere※

※ssh, httpは今回必須です。標準のポートで設定します。
ソースIPアドレスは、スクリーンショットではAnywhere(どこからでもアクセス可能)にしています。(セキュリティの警告が出ますが、今回はこれでOK)。


ec2_step6.png


8.確認画面

これまで設定した内容のサマリ。問題なければ[Launch]クリック。
(警告が出てますが、上記と同様なのでOK)


ec2_step7.png


9.キーペア作成

SSHアクセスに必要なキーペアを作成します。
Create a new key pairを選択しKey pair nameにキーの名前を入力します。
※既に作成済みのキーがあり、それを使用するなら、Choose an existing key pairを選択し、さらにSelect a key pair欄で鍵を選択します。。


ec2_step7_dialog1.png


[Download Key Pair]をクリックすると秘密鍵の書かれたテキストがダウンロードされるので、拡張子を.pemにして保存しておきます。
このあたり、MacとWindowsでは少し違いますので説明します。

Macの場合

MacやLinuxでは、sshの鍵は一般的にユーザのホームディレクトリの下の.sshディレクトリに保存します。(~/.ssh)。
今回はそれに習います。
コピーした.pemファイルは読み取り専用にしておきます(chmod 600)。
通常、.付きのファイルやディレクトリはFinderからは見えませんので、ターミナルで作業します。
以下、Mac上での作業です。

  • sshディレクトリ作成(ない場合)

cd ~/でユーザのホームディレクトリに移動、mkdirでディレクトリ作成。

cd ~/
mkdir .ssh
  • ダウンロードした鍵ファイルをコピー

※鍵のファイル名はstudy_01.pemとしました。

cp ダウンロードした鍵ファイルのフルパス ~/.ssh/study_01.pem
chmod 600 ~/.ssh/study_01.pem

Windowsの場合

今回はputtyを使用した接続を行います。
puttyの場合、ダウンロードした鍵をputty用の形式に変換し、変換後の鍵を使用する必要があるので、いったん好きなところに適当な名前で保存してください。(鍵の変換方法は後述)
※以降のスクリーンショットでは、デスクトップにstudy_01.pemで保存したイメージになっています。

これで鍵の準備はOKです。

[Launch Instances]がクリック出来るようになっていますので、クリックします。


ec2_step7_dialog2.png


10.サーバ完成!

下記画面が出ればOKです![View Instances]をクリックします。


ec2_finish.png


インスタンス一覧に今作成したインスタンスが表示されました!


ec2_view.png


右の方にスクロールすると、[Public IP]が表示されています。
この後、ブラウザからのアクセス、SSHでのアクセスは全てこのIPアドレスに対して行います。
忘れたらこの画面で確認して下さい。


publicip.png


11. ブラウザでアクセスしてみる

http://(public ip)/
にアクセスすると、apacheのデフォルトルートドキュメントが表示されます。


web_test.png


12. SSHでアクセスしてみる

Mac, Windowsでやりかたが違いますので、それぞれ記載します。
※Linuxを使用している方はほぼMacと同じはずですので割愛します。

Macの場合

標準のターミナルを起動します。
/アプリケーション/ユーティリティ/ターミナル
を起動します。

ここからはターミナル上で操作します。

sshを実行し、ec2-userというユーザでログインします。
コマンドラインは下記の通り、ssh -i 秘密鍵のパス ユーザ名@接続先ホスト名(IPアドレス)です。

ssh -i ~/.ssh/ダウンロードした.pem ec2-user@GlobalIP

うまく行けばこんな感じで表示されます。


       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2014.09-release-notes/
25 package(s) needed for security, out of 36 available
Run "sudo yum update" to apply all updates.```

Windowsの場合

puttyを使用します。
手順は、ここに詳しく書かれていますので、その通りでOKですが、実際にやってみたスクリーンショットとともに載せておきます。

ダウンロードした鍵をputty用に変換します。

PUTTYGEN.EXEを起動します。


puttygen.png


[Load]をクリックします。


puttygen_1.png


デフォルトでは、拡張子.pemは表示されないので、[All Files]を選択し、ダウンロードした鍵ファイルを選択し、開きます。


puttygen_2.png


これでOK。


puttygen_3.png


[Save private key]をクリック。


puttygen_4.png


パスフレーズがないという警告が出ますが構わず[はい]。


puttygen_5.png


ファイル名を入力して保存(拡張子は、.ppkにします)。
これで鍵の変換は終了。
※今回はデスクトップの保存していますが、本来はもう少し深いところにおいてください。


puttygen_6.png


sshで接続します。

PUTTY.EXEを起動します。


putty.png


Categoryから[Session]を選択し、下記の通り入力します。

  • HostName ec2-user@GlobalIP
  • Port 22
  • Connection type SSH

putty_1.png


Categoryから[Connection]>[SSH]>[Auth]と選択し、[Browse]ボタンをクリックして作成した.ppkのファイルを選択します。ここまででパラメータ設定は終わりです。続いてこの設定を保存します。


putty_2.png


再び[Session]を選択し、[Saved Sessions]欄に名前を入力し、[Save]ボタンをクリックすると、設定した接続設定に名前をつけて保存することができます。
[Open]をクリックすると接続します。


putty_3.png


こんな画面がでればOK!


putty_4.png


studyユーザを使用する。

次に、作業用として作成したstudyユーザがすでにいますので、そちらで接続します。
今後、作業はec2-userではなく、studyユーザを使用しましょう。
ただし、studyユーザで使用する鍵がありません。
先ほどダウンロードした秘密鍵に対する公開鍵(ec2-user用です)が、/home/ec2-user/.ssh/authorized_keysにあるので、それをstudyユーザ用としても使用するようにコピーしてしまうと楽です。以下、手順です。

まず、上記手順でec2-userでログイン後、管理者(root)に成ります。

sudo -i

※この時はパスワード不要です。

続いて、ec2-userの公開鍵をstudyユーザも使用するようにコピーします。

cp /home/ec2-user/.ssh/authorized_keys /home/study/.ssh/

次に、コピーした鍵のオーナを変更します。

chown study:study /home/study/.ssh/authorized_keys

表示してみます。下記のような表示になっていればOKです。

ll /home/study/.ssh/authorized_keys
合計 4
-rw------- 1 study study 1207  1月 26 12:09 authorized_keys

これでstudyユーザでログイン出来るようになりました。
ec2-userからいったんログアウトし(logoutコマンドまたはキーボードでCTRL+d)、studyユーザでログインしてみます。

ssh -i ~/.ssh/ダウンロードした.pem study@GlobalIP

studyユーザにはパスワードが設定されていますので、管理者になるには、パスワード入力が必要です。

※パスワードはユーザ名と同じstudyが設定されています。

sudo -i
password for study:

と、パスワード入力を求めるプロンプトが出ますので、studyを入力します。

以上でSSH接続はOKです!

セキュリティ的には、studyユーザのパスワードを変更し、ec2-userを削除することをおすすめします。
※今回は必須ではないですが、やり方を載せておきます。

パスワードを変更するには、studyユーザでログイン後、passwdコマンドを叩きます。以下実行例。

[study@ip-172-31-8-2 ~]$ passwd
ユーザー study のパスワードを変更。
study 用にパスワードを変更中
現在の UNIX パスワード:
新しいパスワード:
新しいパスワードを再入力してください:
passwd: 全ての認証トークンが正しく更新できました。
[study@ip-172-31-8-2 ~]$

ec2-userの削除例

studyユーザでログイン後、rootに成ってからuserdelコマンドを叩きます。

[study@ip-172-31-8-2 ~]$ sudo -i
[sudo] password for study:
[root@ip-172-31-8-2 ~]# userdel ec2-user
[root@ip-172-31-8-2 ~]#

GitHubからソース取得

1.fork

元となるリポジトリをGitHub上で自分のリポジトリにコピーします(これをforkといいます)。

GitHubにログインします。


suzukishoutenで検索すると、今回使用するリポジトリが見つかります。


※ほぼ素のままのCakePHPのファイル一式が入った状態です。


github_serch.png


これをforkして自分のアカウントに持ってきます。
赤矢印の[Fork]ボタンをクリックするだけです。


github_fork.png


2.開発用サーバにリポジトリをクローン

Fork後、自分のリポジトリに下記のように、Fork元のファイルがまるごとコピーされています。
赤枠の部分にクローン元のURLがありますのでコピーします。今回はhttpsでのアクセスとしますので、https〜で始まるURLをコピーします。


github_fork2.png


このリポジトリを自分の開発用サーバにCloneします。
studyユーザでsshログインし、/var/www/studyに移動してから下記のようにgit cloneコマンドを叩きます。下記は私のリポジトリの場合のURL。

cd /var/www/study
git clone https://github.com/ks-ocean/rest-study.git
Cloning into 'rest-study'...
remote: Counting objects: 1465, done.
remote: Compressing objects: 100% (810/810), done.
remote: Total 1465 (delta 445), reused 1459 (delta 444)
Receiving objects: 100% (1465/1465), 1.73 MiB | 575.00 KiB/s, done.
Resolving deltas: 100% (445/445), done.
Checking connectivity... done.

これで、/var/www/study/rest-studyにソースがcloneされました。

試しにアクセスしてみます。
http://(GlobalIP) /rest-study
下記のCakePHPのデフォルトページが表示されればOK!。


web_test_cake.png


シンプルTODOアプリ作成

今回は、シンプルなAPIサンプル作成を行い、HTTPリクエストを送受信するツール「POSTMAN」を使用して作成したAPIの動作確認を行うまでをやります。

1.POSTMANの準備

POSTMANはchromeブラウザの拡張機能です。
下記からインストールします。
※インストールしたら、次回起動のためにブックマークしておいてください。

Postman - REST Client - Chrome ウェブストア


postman.png


試しに、QiitaのAPIを叩いてみます。
urlは、
http://qiita.com/api/v2/items?page=1&per_page=20
です。
ちなみに、QiitaのAPIマニュアルは⇢Qiita API v2ドキュメント - Qiita:Developer

結果。


qiita-api.png


この時のqiita.comのサイトを見るとこんな感じ。ちゃんととれている。
これで、作成したAPIのテストが出来ます。


qiita-home.png


2.プログラミング

いよいよプログラミングです。

GithubからCloneしたソースは、/var/www/study/rest-studyにあります。
sshでログインしてcdしてプログラミングを始めます。

そのまえに、URLと、CakePHPのController、 Actionの関係について(重要)

プログラミングに入る前に、RESTアプリケーションにおけるURLと、CakeのController, Actionの関係について軽く整理しておきます。
RESTアプリケーションでは、リソースに対してユニークなURIを割付け、それに対してアクセスします。
そのリソースに対してどのような処理を行うかをHttp Methodで指定します。

(例)

URL
  • todoリストの一覧
    • /rest-study/todo_lists.json
  • todoリストのidが'1'の1件
    • /rest-study/todo_lists/1.json
行う処理
Http Method 処理
GET 取得する
POST 追加する
PUT 更新する
DELETE 削除する

CakePHPのController、Actionを含めまとめると

下表の通り、URL、HttpMethod、行う処理、CakePHPのControllerとActionが対応します。
下に、今回作成するソースを載せていますが、この表の通り作成されています。

URL Http Method 処理 Controller Action
/rest-study/todo_lists.json GET TODOリスト一覧を取得する TodoListsController index
/rest-study/todo_lists/1.json GET TODOリストのidが'1'の1件を取得する TodoListsController view
/rest-study/todo_lists.json POST TODOリストに1件追加する TodoListsController add
/rest-study/todo_lists/1.json PUT TODOリストのidが'1'の1件を更新する TodoListsController edit
/rest-study/todo_lists/1.json DELETE TODOリストのidが'1'の1件を削除する TodoListsController delete

HTTPレスポンスコードについて

APIの処理結果は、HTTPレスポンスコードで返すようにするのが基本です。
大雑把に言うと、

  • 200番台 : 正常終了
  • 300番台 : リダイレクト
  • 400番台 : クライアントエラー
  • 500番台 : サーバエラー

となります。
※参考 HTTPステータスコード - Wikipedia

例)
リソースの追加を行い、成功した場合(POST)は、"201 Created"と返す。

では、プログラミングします!

ソース修正手順

  • 開発用ブランチ作成
    • gitを使用します。git branchで新しいブランチを作ります。
    • 今回は、vol/01という名前にします。
  • ソースを修正する。
    • 修正箇所は後述。vimまたはemacsを使いましょう。
  • POSTMANで動作確認
    • POSTMANを起動し、APIのURLを叩いてみます。
  • phpMyAdminでデータ確認
    • phpMyAdminを起動してデータの中身を見てみます。
  • git初期設定
    • gitのユーザ名とメールアドレスを登録します。
  • git add
    • ファイルをコミット対象にします(ステージング)。git add ファイル名です。git add .とすると変更、追加した全ファイルがステージングされます。
  • git commit
    • ステージングしたファイルをローカルリポジトリにコミットします。この時点ではGitHubには反映されていません。
    • git commitとすると、コミットメッセージを入力する画面がvimで開きます。保存すると続行します。
    • 面倒なので、git commit -m "コミットメッセージ"とすると楽です。
  • git push
    • GitHubアカウントのユーザ名、パスワードを聞かれるので入力します。

という流れになります。

実際にやってみたスクリーンショットを載せます(画面はMacのTerminal)。

開発用ブランチ作成

実行したコマンド

cd /var/www/study/rest-study/
git branch
git branch vol/01
git branch
git checkout vol/01
git branch

1つ目のgit branchはclone直後のブランチ確認、2つ目のgit branchはブランチがvol/01が作成されていることの確認、ブランチ3つ目のgit branchはブランチがvol/01に切り替わっていることの確認です。


dev1.png


ソースを修正する。

まず、app/Config/routes.phpを修正します。
※Vimを使用しました。

実行したコマンド

vim app/Config/routes.php
#〜コピペで編集,保存〜
vim app/Controller/AppController.php
#〜コピペで編集,保存〜
vim app/Controller/TodoListsController.php
#〜コピペで編集,保存〜
vim app/Model/TodoList.php
#〜コピペで編集,保存〜

今回は、下記のソース修正箇所の部分をコピペしました。下記はapp/Config/routes.phpの編集中画面。
他のファイルも同様に vim ファイル名 -> ソースコピペ -> 保存で今回は行きます。 


dev2.png


ソース修正箇所

下記に今回の修正点を書いておきます。
この通り修正すれば動きます!

  • 修正したファイル
    • app/Config/routes.php
    • app/Controller/AppController.php
  • 追加したファイル
    • app/Controller/TodoListsController.php
    • app/Model/TodoList.php
修正ファイルのdiff

※diff表示中の-(ピンク色)の部分は、修正前のソースから削除し、+(緑色)の部分を追加してください。
※コピペする場合は、+の記号を消し忘れないように注意!

app/Config/routes.php
 /**
  * Load all plugin routes. See the CakePlugin documentation on
  * how to customize the loading of plugin routes.
  */
    CakePlugin::routes();

+/*
+ * API
+ */
+Router::mapResources(array (
+   'todo_lists',
+));
+Router::parseExtensions('json');
+
 /**
  * Load the CakePHP default routes. Only remove this if you do not want to use
  * the built-in default routes.
  */
    require CAKE . 'Config' . DS . 'routes.php';
app/Controller/AppController.php
 class AppController extends Controller {
-    public $components = array('DebugKit.Toolbar');
+    public $components = array(
+        'DebugKit.Toolbar',
+        'RequestHandler'
+    );
 }
追加ファイル
app/Controller/TodoListsController.php
<?php

App::uses('AppController', 'Controller');

class TodoListsController extends AppController {

    public function index() {
        $res = $this->TodoList->find('all');
        $this->set(compact('res'));
        $this->set('_serialize', 'res');
    }

    public function view($id = null) {
        $res = $this->TodoList->findById($id);
        $this->set(compact('res'));
        $this->set('_serialize', 'res');
    }

    public function add() {
        $data = $this->request->data;
        $res = $this->TodoList->save($data);
        $this->set(compact('res'));
        $this->set('_serialize', 'res');
    }
    public function delete($id) {
        $res = $this->TodoList->delete($id, false);
        $this->set(compact('res'));
        $this->set('_serialize', 'res');
    }

    public function edit($id) {
        $this->TodoList->id = $id;
        $data = $this->request->data;
        $res = $this->TodoList->save($this->request->data);
        $res = !empty($res);
        $this->set(compact('res'));
        $this->set('_serialize', 'res');
    }

}

app/Model/TodoList.php
<?php

App::uses('AppModel', 'Model');

class TodoList extends AppModel {
}
POSTMANで動作確認

URLを入力します。
http://GlobalIP/rest-study/todo_lists.jsonです。[Send]をクリックします。


postman1.png


でました!予め登録されていた1件です。


postman2.png


※追加、削除、更新も動作しますので、前述のURL, Http Methodのルールに従い、POSTMANの設定を変更して試してみてください。

phpMyAdminでデータ確認

http://GlobalIP/phpmyadmin/index.php
にアクセスします。
ユーザ名study、パスワードstudyでログインできます。


phpMyAdmin1.png


ログイン後、todo_listsテーブルの内容を確認したところ。
POSTMANで確認したデータが1件登録されています。


phpMyAdmin2.png


git初期設定

ここまでで、ソースの修正、動作確認まで終わりました。
ここから、gitへのコミット、さらにGitHubリポジトリに反映させるまで進めます。
まずは設定。ユーザ名とメールアドレスを設定します。
※これをやっておかないとgit commitした時に怒られます。
※ユーザ名、メールアドレスはGitHubアカウントのものと合わせておきましょう。

git config --global user.name "ユーザ名"
git config --global user.mail "メールアドレス"

git config --global --listは設定内容を表示するコマンドです。


dev3.png


git add, commit

下記の通り実行します。

git status
git add .
git status
git commit -m "vol/01 complete"
git status

git status はファイルの編集、コミット/ステージングの状態を表示するコマンドです。
変化がわかるよう実行しています。


dev4.png


git push
git push origin vol/01

※Githubのユーザ名とパスワードを聞かれるので入力します。


dev5.png


これで、GitHubに反映されました。GitHubの画面で確認してみます。
自分のアカウントのトップページに行き、rest-studyリポジトリをクリック。


GitHub_vol01_1.png


ブランチ切り替えのボタンをクリックし、vol/01ブランチを選択。


GitHub_vol01_2.png


app > Controller の順にクリックすると、追加したapp/Controller/TodoListController.phpが表示されました。


GitHub_vol01_3.png


ファイル名の部分をクリックするとソースが表示されます。
※この時のURLは、私のアカウントの場合、
https://github.com/ks-ocean/rest-study/blob/vol/01/app/Controller/TodoListsController.phpです。


GitHub_vol01_4.png


以上です!

うまくいきましたでしょうか?

コメント/フィードバックお待ちしております。

参加者の方も、そうでない方もお気づきの点があればお願い致します。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30