FastAPIで作成したデータをVue.jsで表示させる

# はじめに
フロントエンドのフレームワークの勉強をしようと思い、どのフレームワークを使おうか無限に悩みました。
- React
- Angular
- Vue
- Svelte

断腸の思いで私は**Vue**を選択しました。
なぜかというと学習コストが低そうだから(/・ω・)/
てことで、今回はCluade3を用いてFastAPIで作成したデータをVue.jsで作成するWebアプリケーション側でチャートとして表示したので、まとめていきたいと思います。

# 使用するチャートライブラリ
今回は**ApexCharts**というライブラリを使用していきます。
なぜか？
~~名前がFPSのそれだからだよ~~インタラクティブなチャートを作成でき、かっちょいいと思ったからです。いやほんとに(´・ω・｀)

# それいけClaude3
あとはClaude3に全投げで作成してみました。
編集したファイルは以下の3つです。
- App.vue
- DataChart.vue
- main.py
- main.js

以下のコマンドでまずはVueのプロジェクトを作成しました。
```
$ npm install -g @vue/cli
$ vue create frontend
$ cd frontend
$ npm install --save apexcharts vue3-apexcharts
$ npm run serve
```

また、バックエンドとしてPythonのフレームワークであるFastAPIを使用してデータを作成し、APIを使用します。
まずはFastAPIをインストール。
```
$ pip install fastapi uvicorn
$ uvicorn main:app --port 8080
```

あとはひたすらエラーが出れば投げ、不具合があれな投げの連続。

- **App.vue**
```vue:App.vue
<template>
  <div id="app">
    <DataChart />
  </div>
</template>

<script>
import DataChart from './components/DataChart.vue';

export default {
  name: 'App',
  components: {
    DataChart,
  },
};
</script>
```

- **DataChart.vue**
```vue:DataChart.vue
<template>
  <div id="chart">
    <apexchart type="bubble" height="400" :options="chartOptions" :series="series"></apexchart>
  </div>
</template>

<script>
import apexchart from 'vue3-apexcharts';

export default {
  name: 'DataChart',
  components: {
    apexchart,
  },
  data() {
    return {
      chartOptions: {
        chart: {
          id: 'my-chart',
          type: 'bubble',
          height: 400,
        },
        xaxis: {
          tickAmount: 10,
          labels: {
            formatter: function(value) {
              return value.toFixed(0);
            },
            rotate: -45,
          },
        },
        yaxis: {
          max: 250,
          labels: {
            formatter: function(value) {
              return value.toFixed(0);
            },
          },
        },
        dataLabels: {
          enabled: false,
        },
      },
      series: [],
    };
  },
  async mounted() {
    try {
      const response = await fetch('http://localhost:8080/data');
      const data = await response.json();
      console.log('Fetched data:', data);
      this.series = [{
        name: 'Bubble Chart',
        data: data.values.map((value, index) => ({
          x: value.x,
          y: value.y,
          z: value.z,
          name: data.categories[index],
        })),
      }];
      console.log('Chart data:', this.series);
    } catch (error) {
      console.error('Error fetching data:', error);
    }
  },
};
</script>
```

- **main.py**

```python:main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import random
import string

app = FastAPI()

# CORSの設定
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:8081"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

def generate_random_string(length):
    letters = string.ascii_uppercase
    return ''.join(random.choice(letters) for _ in range(length))

@app.get("/data")
def get_data():
    categories = [generate_random_string(3) for _ in range(100)]
    values = []
    for _ in range(100):
        x = random.randint(10, 200)
        y = random.randint(20, 300)
        z = random.randint(5, 50)
        values.append({"x": x, "y": y, "z": z})
    data = {
        "categories": categories,
        "values": values
    }
    return data

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8080)
```

- **main.js**
```js:main.js
import { createApp } from 'vue';
import App from './App.vue';

createApp(App).mount('#app');
```

APIの知識がほとんどないため、ポート番号の通し方などでめっちゃ苦戦しましたが、無事チャートを表示することができました！

![chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/31350f6b-54d7-94cc-88cf-d478d91e5048.png)

めっちゃヌルヌル動いて気持ちいいです。
Plotlyより全然良い( ;∀;)

# まとめ
今回はまったくの初心者がWebアプリケーションを作成しましたが、すべてClaude3様が作ってくれました(´・ω・｀)
なので、中身についてはさっぱりです！！！（笑）
ちゃんと中身も分解しながら理解しようと思います。
頼むぜ相棒（Claude3）
今後はWebアプリケーションの作成もちょくちょく行っていこうと思いますので、どんどん困ったことは発信していこうと思います！
それでは！！！