Sinatra、nginx、MySQLを用いたToDoアプリの開発

# 環境
Ubuntu 20.04 LTS(WSL2)

# はじめに
今回の記事は参考文献のUdemyの内容を一部抜粋して、Sinatra、nginx、MySQLを用いたアプリケーションの開発となっています。
ただ、Udemyの内容のため、具体的なコードなどを載せる、ということは極力控えたため、だいぶ分かりにくくなってしまったかもしれませんm(__)m
もし本記事を読んで、興味をもっていただけた方がいましたら、参考文献のUdemyの講座を受講してみることをオススメします！



# nginxの準備とHTMLの実装
まずはnginxを動かしてみましょう

## インストール方法
```
$> sudo apt update
$> sudo apt install nginx
```

## nginxの起動
```
# 起動コマンド
$> sudo nginx
```

「localhost」にアクセスしてnginxのデフォルトページが表示されれば成功です

## nginxの停止、再起動
```
# 停止コマンド
$> sudo nginx -s stop
# 再起動コマンド
$> sudo nginx -s reload
```

## HTMLの実装
nginxのインストールに成功したら、次は基本的なHTMLの実装をしてみましょう
まずは以下のコマンドでディレクトリ移動してみましょう
```
$> cd /var/www/html
```
すると、中にhtmlファイルが格納されているのが分かります。
そのファイルを削除して試しにindex.htmlというファイルを作ってみましょう(もしくは元々あったファイルの中身を変更する)

今回は試しに簡単なToDOアプリの開発なのでよさげにHTMLを書いてあげましょう
今回はSinatraでバックエンドの処理も実装し、jsonの受け渡しを行うため、javascriptの処理も必要となります。なので
```
<script src="main.js"></script>
```
の一行をbodyタグの終わる直前に記述しました。
したがって、「main.js」というファイルも同じディレクトリ内に作成しておきましょう。(まだ中身は空で大丈夫です)

ここまで終わったら、「localhost」にブラウザ上でアクセスすると、あなたが実装したHTMLを見ることが出来ると思います！

ここまで確認できたら、次はSinatraでバックエンドの開発を行っていきましょう

# Sinatra、MySQLを用いたバックエンドの開発
## Sinatraのインストール
まずはrubyをインストールしましょう

```
$> sudo apt install ruby
$> sudo apt install ruby-bundler
```

ここまで終わったら、rubyとそのライブラリを管理するツールがインストールされたはずです。なので次にSinatraをインストールしていきます。

まず開発を行いたいディレクトリ下で以下のコマンドを実行します
```
$> bundler init
```
するとディレクトリ下に「Gemfile」が生成されます。
このGemfileを編集することで、rubyライブラリのインストールが行えます。
なのでGemfileの一番下に以下の行を挿入してください
```
gem "sinatra", "2.2.0"
```
これはsinatraというライブラリのバージョン2.2.0をインストールしてね、という処理になります。
ここまで出来たら、そのディレクトリ内で以下のコマンドを実行します
```
$> bundle install
```
これでSinatraのインストールが終わりました。

## MySQLのインストールとDBの作成
次にDBとなるMySQLをインストールしていきます

```
$> sudo apt install mysql-server
$> sudo service mysql start
```
ここまで行うとMySQLが立ち上がります。
では次に今回のアプリで使用するDBとそのテーブルを作成していきましょう

```
$> sudo mysql
```
上記のようにコマンド入力することで、MySQLをいじれるようになります。
なのでここからDBを作成していきましょう。
今回はとりあえず「ID」、「タイトル」、「作成日時」を持った「tasks」テーブルを作成していきます

```
mysql> create database データベース名;
mysql> use データベース名; 
mysql> create table tasks(
    -> id int primary key auto_increment,
    -> title varchar(255) not null,
    -> created_at timestamp not null default current_timestamp
    -> );
```

これで今回のアプリケーションで使用するDBとそのテーブルの作成が完了しました。
あと、SinatraからMySQLにアクセスできるようにユーザを作成しておきましょう
```
mysql> create user 'ユーザ名'@'%' identified by 'パスワード'
```
これでMySQL側の設定は完了です。

次に作成したDBにSinatraでアクセスできるようにします。

```
$> sudo apt install ruby-dev
$> sudo apt install build-essential
$> sudo apt install libmariadb-dev
```
ここまで終わったら次に先ほどSinatraをインストールするために編集したGemfileを再度編集し、MySQLを入れます。
Gemfileの最後に以下の一行を挿入してください。
```
gem "mysql2", "0.5.2"
```
これでSinatraからMySQLにアクセスできるようになりました。

## バックエンドの開発

ここまで終わったらついにバックエンドの実装にとりかかっていきます。
今回実装する処理は以下の2つです
①GETで「/api/tasks」というパスにアクセスしたときにtasks一覧を返す処理
②POSTで「/api/tasks」というパスにアクセスしたときにtasksに新しいデータを追加する処理
```
require 'sinatra'
require 'mysql2'

# ①GETで「/api/tasks」というパスにアクセスしたときにtasks一覧を返す処理
get '/api/tasks' do
  client = connect

  result_set = client.query('select id, title, created_at from tasks')
  tasks = result_set.map do |row|
    {
      id: row['id'],
      title: row['title'],
      createAt: row['created_at']
    }
  end

  client.close

  {
    tasks: tasks
}.to_json
end
# ②POSTで「/api/tasks」というパスにアクセスしたときにtasksに新しいデータを追加する処理
post '/api/tasks' do
  request_body = JSON.parse request.body.read

  title = request_body['title']

  client = connect

  statement = client.prepare('INSERT INTO tasks (title) values (?)')
  statement.execute(title)

  client.close
end

def connect
  Mysql2::Client.new(
    :host => "ホスト名",
    :database => "データベース名",
    :username => "ユーザ名",
    :password => "パスワード",
    :connect_timeout => 5
  )
end

```

これでGET、POST時の処理が完了しました。
connect関数はDBに接続するための処理です。ユーザ名などは自分で設定したものを入れるようにしてください。

ここまで終わったら、このファイルを実行してアプリケーションサーバを以下のコマンドで起動してみましょう。
```
ruby ファイル名
```
ここのファイル名はSinatraの処理を記述しているファイル名のことです。

あとはnginxでこのAPIにアクセスできるように設定する必要があります。
「/etc/nginx/sites-enabled/default」ファイルを編集します。
中を見てみると
```
location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }
```
という部分があるのでこの直後に以下のコードを追加します。
```
location /api/ {
                proxy_pass ホスト名;
        }
```
ホスト名のところには各々のものを入力します。
(ローカルで動かしている場合はlocalhost:4567になると思います。ポート番号についてはSinatraの処理を記述したファイルを実行する際に出てきます。)

これで、簡単なものではありますがアプリケーションサーバーが完成しました。
では最後にこのアプリケーションサーバーから送られたJSONをブラウザ上で表示するためのjavascriptの処理を書いていきましょう。

# javascriptの実装
ここまできたらあとはJSONを受け取って、HTMLに渡す処理だけです。
最初の方に作ったmain.jsを編集していきましょう。

作成する処理は先ほどと同様で
①tasksのデータを全部持ってきてHTMLに変換する処理
②入力されたデータをJSONとして「/api/tasks」にPOSTとして渡す処理

```
# ①tasksのデータを全部持ってきてHTMLに変換する処理
async function loadTasks() {
    処理内容を記載
}

# ②入力されたデータをJSONとして「/api/tasks」にPOSTとして渡す処理
async function registerTask() {
    処理内容を記載
}

async function main(){
        フロント側で入力フォームのクリック時にregisterTasksを実行する処理
        await loadTasks()
}

main()
```

ここまでいけば動くものができたと思います！お疲れ様でした！
![スクリーンショット (140).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1193085/b85a54de-822e-ee96-86eb-b3ccd0ff18ed.png)

# 個人的に躓いた点
SinatraからMySQLにアクセスしようとすると何度も以下のようなエラーが出ました
```
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
```
原因として考えられるのは、MySQLが起動していなかった、ということが挙げられます。
今回、私の記事で書いたように
```
$> sudo service mysql start
```
を実行し、MySQLを起動したことで解消されました。

# まとめ
今回のこのアプリケーションは参考文献のUdemyの内容から一部抜粋させていただいております。Udemyの講座の内容のため、具体的なコードを載せるのはなるだけ控えたため、だいぶ分かりにくくなってしまいました、申し訳ありませんm(__)m
よかったら参考文献に載せてますUdemyの講座を受講していただくとだいぶ理解が深まると思います(Udemyの回し者じゃないです、ﾊｲ)
今回はCRUDのうち、C(create)の部分しか実装していませんが、同じ要領で残りのRUDも実装できるので、是非挑戦してみてください、お疲れさまでした！

# 参考文献
https://www.udemy.com/course/docker-from-linux-and-networking/?utm_source=adwords&utm_medium=udemyads&utm_campaign=DSA_WebIndex_la.JA_cc.JP&utm_content=deal4584&utm_term=_._ag_89101504074_._ad_439843892593_._de_c_._dm__._pl__._ti_dsa-454026085647_._li_1009250_._pd__._&gclid=CjwKCAjwjMiiBhA4EiwAZe6jQ-jOwYDfKm2GVmVIi1iuayncu4bNUGfTjBBzu-_0jUUpGvMREk9PUBoCwFkQAvD_BwE

https://rooter.jp/infra-ops/organizing-mariadb-login-error/