Safie Engineers' Blog!

Safieのエンジニアが書くブログです

ゼロから学んだフロントエンド実装

はじめに

こんにちは。2025年度新卒入社しました川上達也です。

この記事では新卒開発研修の中で個人的に開発したRaspberry Piを使ったアプリについてお話しします。

私のこれまでの開発経験はPythonによるAI開発のみで、バックエンドやサーバーサイドといった概念も考えずに開発していました。

入社後に行う開発研修では新卒エンジニア7人で社内課題を解決するプロダクトを作ります。このプロダクト開発をチームで円滑に行うために、開発を始めるより先に新たな技術領域を身につける必要がありました。

そのためプロダクト開発に先駆けてプレ開発として、「近くでも遠くでも忙しさがわかるアプリ」を作りました。近くにいるときはRaspberry Piの画面で、遠くにいるときはSlackのステータスで「忙しい」、「話しかけてもいいよ」、「お昼寝中」の3つの業務状態を確認できます。

この記事ではプレ開発を通して身につけたフロントエンド開発の成果を伝えようと思います。

作ったもの

今回、SlackのステータスをRaspberry Piから更新するアプリを作りました。Raspberry Piに接続したタッチディスプレイから入力を行い、Slackのステータスの更新を行います。 実際に使っている様子は次の画像のようになります。

アプリを起動すると次の画像の左側のようにStartと書かれた状態で画面が表示されます。この状態はSlackのステータスには影響を与えません。

その後3つのボタンを押すとそれぞれのボタンに対応したステータスにSlackとWebクライアントで更新が行われます。

この時にSlackでも更新が行われます。

システムの説明

アプリのユースケース図を示します。

ユーザーがステータスの入力を行うと、そのステータスをWebクライアントで表示します。

そしてシステム構成は次のようになります。

Raspberry Piでユーザーの入力を処理するWebクライアントとSlackサーバーにリクエストを送信してステータスを更新するAPIサーバー両方の機能を持っています。 WebクライアントはReactで、APIサーバーはFastAPIで実装しました。

動作の説明

ここでWebクライアントを実装するReactの処理とSlackステータスの更新を行うFastAPIの処理を説明します。

Reactの処理

  1. 入力処理 予め想定してある3つのステータスに合わせたボタンを3つ生成します。それぞれのボタンにonClickイベントとkeyを設定しておき、押されたボタンに応じたステータス表示とリクエストの送信を行います。

      const Status = ["busy", "free", "sleep"]
    
      {Status.map((work) => (
          <button className="btn-color" key={work} onClick={() => onClickButton(work)}>
            {work}
        </button> 
      ))}
    
  2. ステータス表示 useStateを使い、押されたボタンの持つkeyに対応する画像と文字列をそれぞれ状態として表します。ボタンが押された時に状態の更新が行われ、新たな画像と文字列が状態に設定されます。そして状態が変更されるとレンダリングが実行され、画面に表示されるステータスが変更されます。

      const onClickButton = (work:string) => {
          const [workStatus, setWorkStatus] = useState<string>("Start");
        const [imgPath, setImgPath] = useState<string>(sunImg);
    
        setWorkStatus(work)
    
        if (work === "busy"){
          setImgPath(busyImg)
        }else if (work === "free"){
          setImgPath(freeImg)
        }else if (work === "sleep"){
          setImgPath(sleepImg)
        }
        send_request('http://localhost:8000/api/update_status', work)
      }
    
  3. リクエストの送信 fetch APIを使ってReactからFastAPIへPOSTリクエストを送信します。その際にasync/await構文を使い、非同期処理を実装します。このPOSTリクエストでは押されたボタンに対応するkeyを送信します。

      const send_request = async (req:string, work:string) => {
        try {
            const requestOptions = {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ work: work })
            };
            fetch(req, requestOptions)
            .then(response => response.json())
          } catch {
        console.log("error")
        }
      }
    

FastAPIの処理

  1. ステータスのセット FastAPIではまずReactからPOSTリクエストを受け取ります。このPOSTリクエストではユーザーが押したボタンに対応するkeyを受け取ります。このkeyを使い、Slackサーバーに送信するためのtextステータスとemojiステータスを設定します。textステータスとemojiステータスをSlackサーバーに送信すると、textステータスはそのままステータスの文字として、emojiステータスはemojiステータスに対応した絵文字として、ステータスが更新されます。

      from fastapi import FastAPI, Query
      from slack_sdk import WebClient
    
      @app.post('/api/update_status')
      async def UpdataStatus(data: Work):
        SLACK_BOT_TOKEN = "xxx"
    
          if data.work == "busy":
              status_text = data.work
          status_emoji = ":working-in-office:"
          elif data.work == "sleep":
          status_text = data.work
          status_emoji = ":zzz:"
          elif data.work == "free":
          status_text = data.work
          status_emoji = ":good-nya:"
    
  2. リクエストの送信

    slack_sdkWebClientを使って、textステータスとemojiステータスをユーザーのtokenとともにSlackサーバーへ送信します。Slackサーバーが受け取ったtokenによりユーザーを識別して、ユーザーのステータス更新が行われます。

         client = WebClient(token=SLACK_BOT_TOKEN)
    
         try:
           response = client.users_profile_set(
           profile={
             "status_text": status_text,
             "status_emoji": status_emoji,
             "status_expiration": 0
           })
         except Exception as e:
         print(f"unexpected error: {e}")
    

このようにして更新されたステータスはSlackとWebクライアントで次の画像のように表示されます。

💤 sleepとなっているところがステータスです。SlackでもWebクライアントでも同じステータスを表示することができます。

また更新可能な3つのステータスはそれぞれ次の業務状態を想定しています。

  • 忙しい時・作業に集中したい時

  • 余裕のある時

  • お昼寝中

所感

このアプリ実装を通して、これまで開発経験のなかったフロントエンドやAPIの実装をすることができました。ReactとFastAPIを連携させましたが、React単体でも実装できるアプリであったのでFastAPIを使う必要はありませんでした。今回は「エンジニアとして成長する」という研修の目的を意識しReactとFastAPIを連携させる構成を選択してより多くの技術に触れました。この構成は、それぞれの技術の役割分担や連携方法を学ぶ上で非常に有益でした。一方でどのような技術選択が最適なのかを考えることも、今後は行わなければならないところではあります。

現在私は開発研修の中でチームのふりかえり会の運営を担当しています。ふりかえり会の一つとしてチームメンバー同士で褒め合うことをしました。その進行方法は、次のように設定しました。

この進行を1ターンとしてチームメンバー全員が褒める人褒められる人の両方を担当する1セクションを繰り返します。

この会を盛り上げながら、円滑に行うために次の画像のようなアプリを開発しました。

抽選ボタンを押すと、褒める人褒められる人をランダムで抽選します。表示を押すとターンが進行して、抽選された褒める人褒められる人が表示されます。

再び抽選ボタンを押すと、褒める人褒められる人の抽選が行われセクションが進行します。抽選ボタンを押して行う抽選はバックエンドで実装しました。その際に”すでに行った褒める人褒められる人の組み合わせになる抽選は行わない”という制約を持たせました。バックエンドのPythonでこの機能を実装することで、短い時間でアプリを作ることができ、役割分担を考えて技術選定を行えました。

初めてのフロントエンド実装を通して得た学びを糧に新たなアプリを作ることができました。これからもユーザーにとって価値あるプロダクトを開発できるエンジニアを目指して、学習を続けていきます。

また私は入社前に自身の開発経験の少なさを不安に思っていました。現在はこの記事で説明したプレ開発や開発研修での学びを通してエンジニアとしての成長を感じています。この記事を読んで入社後の不安を抱えている学生や就活生の助けになればいいと思います。

25年度新卒研修に関する記事はこちらをご覧ください。

  1. 2025年、新卒エンジニア研修はじめました
  2. Notion初学者のためのショートカット活用術:業務効率を上げる第一歩
  3. 100人をマネジメントした指揮者が 新卒で挑戦した「不確実性」と向き合うチームビルディング
  4. 新卒一年目のエンジニアが感じた、プレ開発で見えたチームの“成長”
  5. ゼロから学んだフロントエンド実装
  6. 毎日の日報報告をワンボタンで
  7. ハッカーの視点を身に付ける!新卒が学んだセキュリティ研修

© Safie Inc.