【React(TypeScript)&Sinatra】React(TypeScript)からSinatraで作成したAPIを叩く

React(Typescript)からSinatraで作成したAPIを叩いて、データを取得して展開するみたいな実装をしたのでまとめておきます。TsやSinatraはそんなに経験がないので、間違いがあれば指摘お願いします。

## やること
- React+TypeScriptでコンポーネント作成時に、Sinatra上で作成したAPIからデータを取得して、表示するまでの流れ。

## 対象者
- APIサーバーとフロントサーバーを切り離した時のデータのやり取りについて知りたい人。
- Sitatra上でのAPI作成について知りたい人。
- React + TypeScriptでのデータの取得からの展開の仕方について知りたい人。

## 扱うこと
- SinatraでのAPI作成方法
- React(TypeScript)側での取得方法
- 取得データをReact側で表示させるまでの流れ

※環境構築には触れないのでご了承ください。

## SinatraでAPI作成
Sinatraの基本知識は以下のサイトで確認！
http://sinatrarb.com/intro-ja.html

ここからはAPI部分のみ記述していく。app.rbに以下の感じで書いていく。例として、nameカラムを持つUserテーブルから全てのデータを取得することを想定する。

```ruby:app.rb
get '/users' do
  @users = User.all
  return @users.to_json
end
```

のちにcorsで困ることになるので、以下のように変更。corsについては以下の記事参照。
https://qiita.com/tomoyukilabs/items/81698edd5812ff6acb34

```ruby:app.rb
before do
  response.headers['Access-Control-Allow-Origin'] = '*'
end

get '/users' do
  @users = User.all
  return @users.to_json
end
```

## React(Typescript)でAPIを叩く
先のコードを示す。以下、解説を加えていく。

```ts
import * as React from "react";
import axios from "axios";
import camelcaseKeys from 'camelcase-keys';

interface User {
  id: number;
  name: string;
}

interface State {
  users: User[];
}

class User extends React.Component<State> {
  constructor() {
    super();
    this.state = {
      users: []
    };
  }

  componentDidMount() {
    const url = `https://domain_name/users`
    axios.get(url)
    .then((results) => {
      const data = results.data
      const users = data.map((d: object[]) => {
        return(camelcaseKeys(d))
      })
      this.setState({
        users
      })
    })
    .catch((data) => {
      console.log(data)
    })
  }

  render() {
    const { users } = this.state;
    return (
      <div className="hello">
        <p>Users</p>
        {users.map((user) => {
          return (
            <div key={user.id}>
              <p>{user.name}</p>
            </div>
          )
        })}
      </div>
    );
  }
}

export default User;
```

## 必要なライブラリのimport
以下のコードで必要なライブラリをimport。ReactはComponentを作成するために必要なもの、axiosはAPIを叩くために必要、camelcaseKeysはSinatraから取得したsnake_caseで表現されているデータを書き換えるために必要。

```ts
import * as React from "react";
import axios from "axios";
import camelcaseKeys from 'camelcase-keys';
```

## 型の定義とStateの準備
取得するデータの型とデータを入れるためのStateの準備。今回取得するデータはidカラムとnameカラムを持つUserなのでその旨を定義する。そしてusersをStateに記述する。

```ts
interface User {
  id: number;
  name: string;
}

interface State {
  users: User[];
}

class User extends React.Component<State> {
  constructor() {
    super();
    this.state = {
      users: []
    };
  }
```


## APIを叩く場所
以下のコードでAPIを叩いている。ReactでAPIを叩きたいときはaxiosを利用してgetリクエストを該当urlに投げて結果を取得する。取得するときにhashデータのkeyをsnake_caseからcamel_casenに直す(rubyではsnake_case推奨だがjsでは違う)。componentDidMountについては以下の記事参照。
https://qiita.com/megane42/items/213e927a2af72530e920

```ts
  componentDidMount() {
    const url = `https://domain_name/users`
    axios.get(url)
    .then((results) => {
      const data = results.data
      const users = data.map((d: object[]) => {
        return(camelcaseKeys(d))
      })
      this.setState({
        users
      })
    })
    .catch((data) => {
      console.log(data)
    })
  }
```

## データの展開とexport
データを展開してexportする。

```ts
render() {
    const { users } = this.state;
    return (
      <div className="hello">
        <p>Users</p>
        {users.map((user) => {
          return (
            <div key={user.id}>
              <p>{user.name}</p>
            </div>
          )
        })}
      </div>
    );
  }
}

export default User;
```

## 最後に
ずっとRuby(Rails)使いだったので、TSは非常に新鮮で楽しい。Rubyしか使ったことのない人は型とかのいい勉強になると思うのでオススメです。