[個人開発] 過去の天気を簡単にグラフ化できるサービスを作ってみた。

### はじめに
過去の天気を閲覧できるWebアプリを作成しましたので技術的な部分に関して紹介していきます。

### 概要
- サービス名：かこてん。
- URL：https://kako-ten.com/
- コンセプト：過去の気象データを誰でも簡単に可視化・比較ができるサイト
- バックエンド：AWSサーバレス環境 (Lambda/Python, API Gateway, DynamoDB, SAM等)
- フロントエンド：React/Typescript, VITE, MUI, canva等
- インフラ：AWS, CloudFront, S3, Cloudwatch, Cloudformation等
- CICD：Github Actionsによる自動ビルド・テスト・デプロイ
- Github: https://github.com/y-o-shi/kakoten-web-front (フロントのReactコードのみ公開)

### サービス内容
全国約1200地点の気象庁アメダス観測所の過去のデータを非常に簡単な操作でグラフ化できます。単一地点を選択するモードと、複数地点を比較するモードの2種類があり、スマホからPCまでのレスポンシブ対応しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620936/daf5aa70-3906-cb7f-e4a5-9417e161d4e5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620936/41f76c72-3763-16c8-e56b-44e0d71f054b.png)

### 制作動機
個人的に過去の天気を調べたりすることが多いのですが、過去の天気を調べることができる主なサービスは対象データに行き着くまでの操作回数が多いと感じていました。また、データを可視化したり他の地点や日付と比較をするには CSV データとしてダウンロードしてエクセル操作する必要があり、ダウンロードする操作も少し複雑で、インターネットに慣れていない人にとっては難しいと感じる可能性もあると感じていました。
そこで、自分も利用したいという動機もあり、「誰もが簡単操作で過去の気象データを可視化できるサイト」を作ることを決意しました。
「異なる観測地点、異なる日付の気象データを1つのグラフ画面に描画できるサービス」は私が調べた限り日本で初でした。万人受けするようなサービスではないかと思いますが、過去の気象データ分析はエネルギー業、農業等を始めとして色々な分野で求められていることなので、数百人～数千人に1人でもいいので便利だと思っていただければ幸いだと思いサービスを継続して行きたいと思います。

### アーキテクチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620936/6532bb09-4c26-f75c-7aaf-a2dcc1c73ea2.png)

フロント部分のS3+CloufFrontも、サーバレスバックエンド部分のAPI Gateway, Lambda, DynamoDBもかなりスタンダードな構成だと思います。気象庁APIがあるならこのサービス用のDBはいらないんじゃ？と思われるかもしれませんが、気象庁APIからは過去10日分ぐらいの気象データしか参照できないため、そのデータをDynamoDBに格納することで過去の任意の日付のデータを閲覧できるようにしています。
 また、気象データ取り込み時にEventBridgeからSQSを介してLambdaを実行している理由は、約1200地点の1日分のデータを取得するためにPythonの実行時間が1時間程度かかり、Lambdaがタイムアウトになってしまうからです。SQSを使って200地点程に分割してデータを取得していくようにしています。

### 技術要素
- バックエンド(AWS 完全サーバレス)
  - Lambda (Python3.11)
  - API Gateway (REST API)
  - DynamoDB (No SQL データベース)
  - SNS (E メール通知)
  - S3 (DB バックアップ)
  - SAM (IaC)
  - Cloudwatch (アラーム設定)
- Web アプリデプロイ環境 (AWS)
  - CloudFront (CDN 配布)
  - Route53 (ドメイン設定)
  - ACM (SSL 認証)
  - S3 (静的 Web 公開)
  - CloudFormation (IaC)
- フロントエンド開発
  - React / Typescript / Vite / Docker
  - useRecoil (状態管理ライブラリ)
  - MUI, ReCharts (UI ライブラリ)
  - Canva (アイコン＆作成)


### バックエンドのサーバレスの採用理由
バックエンドはEC2, ECS (Fargate), サーバレスの3種類で悩みました。最終的にはコストを理由にサーバレスを選択しました。
継続的な運用をするためにコストを徹底的に下げることは必須要件であると考え、コストに重点を置いてアーキテクトを組みました。EC2やECSの場合は最小構成でも月1000円程度はかかってしまいますが、サーバレスの場合はサービスが小さい内は API Gateway, Lambda, Dynamo を主軸にした構成で月数円～十円で済むようになります。毎日に数万アクセスまでは耐えるように設計し、1日の間にそれ以上のAPIアクセスがあった場合は大量課金を防ぐために自動で API アクセスが閉じるようにし、翌日に再稼働するようにしています。また、アクセス負荷が大きい場合には個人メール宛てにアラーム通知を出すようにしたり、お問い合わせフォームに reCAPTCHA 認証を加えたり、REST API の呼出し権限を考えたりと、セキュリティとリスク管理には手を入れました。

余談ですが、サーバレスのメリットの1つに、高負荷なリクエストがあったとしてもサーバが落ちずに処理できてしまう点がありますが、それはそのままデメリットにもなります。どういうことかというと、サーバ環境であったらサーバが落ちるほどの膨大なリクエストを受けても処理できてしまうため、Dos攻撃等を受けたときに従量課金であるサーバレスでは高額な請求となってしまう可能性があります。そのため、APIGatewayのAPIキーやCORSによる設定は当然ですが、Frontドメイン以外からは徹底的に拒否する設定やレート・バースト・クォータによるリクエスト制限等にはかなり気を使わなければなりません。

### 工夫した点
##### マイクロサービスの疎結合アーキテクト
バックエンド、Web デプロイ環境、フロントエンドソースコードは Git で別リポジトリとして管理しています。それぞれの依存性を低くすることで耐障害性、拡張性、保守性を向上させています。

##### CICD
Github Actions によるビルドテストや自動での S3 デプロイを構築し、開発からデプロイまでの作業を効率化しました。

##### インフラコード管理(IaC)
AWS リソースのほとんどは Cloudformation, SAM によりコード化しています。それにより、全体的な保守性の向上や、時間が経った後に拡張・改修する際にリソースの中身を把握することが容易になると思っています。

##### UI・UX
実務でもよく扱っている React を使い、短い工数でユーザの利用性を向上できるように努めました。コンセプトに合わせて誰でも簡単にグラフ操作ができるように、学習コストが必要な機能を入れず、"目立たないが地味に便利な直感的機能"を多く作りました。その中でも特に、観測地点選択画面と、グラフ画面に大きく力を入れました。

観測地点選択画面では、観測地点が約 1200 点あるため、どのように選択していただくかを考え、「都道府県からの選択」、「観測所のテキスト検索」、「主要都市」、「履歴」の 4 種類から選ぶことできるようにしました。また、観測地点によって存在する気象データが異なるため、観測地名横に A ～ F の文字を振り、どのタイプの気象データを持つかを一目で判断できるようにしました。また、複数地点比較での選択画面では一度に 4 地点まで選択できるようにし、上述の 4 種類からの選択を組み合わせて選択できるようにし、そのために今自分が選択中の観測地名を下に固定表示するようにし、利便性を上げました。
グラフ画面では、1 日 ～ 4 日 までの気象データを比較でき、グラフの左軸だけでなく右軸も選択可能にすることで同時に 8 種データを同時描画できるようにしました。また、凡例をクリックして 1 種データずつの表示・非表示の切替を可能する、全データをまとめて日付移動できるボタンを用意する、矢印ボタンのみで日付移動ができるようにしてカレンダーを開いて操作する手間を減らす、降水量は棒グラフで他データは折れ線グラフにする、右軸は一度有効にした後ももう一度同じボタンを押せば無効にできる等、"目立たないが地味に便利な要素"を多く取り入れて利便性の向上を図りました。

### 最後に
あまり多くの人に需要があるとは言えないかもしれませんが、過去の天気を簡単に可視化してみたいというようなときには是非使ってみてください！