Jiraは、プロジェクト内のタスクを追跡するのに便利な人気のプロジェクト管理ツールです。しかし、大規模なプロジェクトに取り組むと、タスクやチームメンバーの数が増えるにつれ、Jiraダッシュボードが乱雑になることがあります。

これに対処するために、Jira REST APIを使用して、割り当てられたタスクとその期限を表示する簡略なToDoリストアプリケーションを構築してみましょう。このAPIを使用することで、Jiraとプログラムを介して連動し、課題の作成、取得、更新、削除、ユーザーデータやプロジェクト情報へのアクセスができるようになります。

今回の記事では、Jiraアカウントから課題をフェッチするサーバーとしてNode.jsを使用し、それを表示するReactアプリケーションを使用した ToDoリストの開発についてご説明します。また、フロントエンドとサーバーの両方をKinstaにホストする方法にも触れます。

前提条件

手順に従うには以下のものが必要です。

Node.jsとExpressでバックエンドを構築する方法

Expressは、サーバーサイドアプリケーション構築を合理化する、人気のNode.jsフレームワークです。Expressは、ルートの処理を簡素化し、API、データベース、フロントエンドアプリケーションなどの外部リソースとのやり取りを容易にします。

以下の手順に従って、サーバーをセットアップしてください。

  1. 新しいディレクトリを作成し、そこに移動します。次に、以下のコマンドを実行してNode.jsを初期化してください。
    npm init -y

    このコマンドは、デフォルト設定のpackage.jsonファイルをアプリのフォルダのルートに作成します。

  2. 次に、以下のコマンドを実行して、プロジェクトに必要な依存関係をすべてインストールします。
    npm install express dotenv axios

    上記のコマンドで以下がインストールされます。

    • express:APIを構築する最小限のNode.jsフレームワーク
    • dotenv.env変数をprocess.envに読み込み、安全にアクセスできるようにするモジュール
    • axios:Node.jsのプロミスベースのHTTPクライアント(JiraへのAPI呼び出しを行うために使用します)
  3. インストールが成功したら、プロジェクトのルートに.envファイルを作成し、PORT番号を追加します。
    PORT=3000

    これはサーバーがリッスンするポート番号です。お好きなポート番号に変更してください。

  4. プロジェクトのルートフォルダにindex.jsファイルを作成し、以下のコードを追加してExpressをインポートし、Expressアプリケーションのインスタンスを作成してサーバーを起動します。
    const express = require('express');
    require('dotenv').config()
    const app = express();
    const PORT = process.env.PORT;
    
    // ここでルートを定義
    
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}`);
    });
  5. 最後に、package.jsonファイルに、サーバーを起動するスクリプトを追加します。
    "scripts": {
       "start": "node index"
      },

    これで、ターミナルで起動スクリプトを実行できるようになります。

    npm run start

    このコマンドでサーバーが起動します。ターミナルに以下のテキストが記録されているはずです。

    Server is running on port 3000

    サーバーを起動して実行すると、Jiraアプリを設定できます。

Jiraアプリを設定する方法

Jira REST APIを使用するには、Jiraサイトでユーザーアカウントを認証する必要があります。構築したToDoアプリAPIでは、AtlassianアカウントのメールアドレスとAPIトークンによる基本認証を使用します。

設定方法は次のとおりです。

  1. Jiraアカウントを作成するか、アカウントをお持ちの場合はログインします。
  2. Atlassianプロファイルのセキュリティセクションに移動し、「API トークンの作成」をクリックします。
  3. 表示されるダイアログでトークンのラベルを入力し(例:”jira-todo-list”)、「作成」をクリックします。
  4. トークンをクリップボードにコピーします。
  5. 最後に、.envファイルにAPIトークンを保存します。
    JIRA_API_TOKEN="your-api-token"

    これで、基本認証を使用してJira APIにアクセスできます。

Jiraから課題をフェッチするルートのセットアップ

これでJiraアプリケーションを設定しました。Node.jsサーバーでJiraから課題をフェッチするルートを設定しましょう。

Jira APIへのリクエストを開始するには、.envファイルに保存したJira APIトークンを使用する必要があります。process.envを使用してAPIトークンを取得し、index.jsファイルのJIRA_API_TOKENという変数に割り当てます。

const JIRA_API_TOKEN = process.env.JIRA_API_TOKEN

ここで、APIリクエストのエンドポイントURLを定義する必要があります。このURLはJiraドメインとJira Query Language(JQL)ステートメントを含みます。JiraドメインはJiraにおける組織URLを指し、org.atlassian.netのようになります。orgは組織の名前です。一方、JQLはJiraの課題と対話するクエリ言語です。

Jiraドメインを.envファイルに追加することから始めます。

JIRA_DOMAIN="your-jira-domain"

また、Jiraにリクエストを行う際の認証に使用されるため、.envファイルにJiraメールを保存する必要があります。

JIRA_EMAIL="your-jira-email"

次に、両方の環境変数を追加し、ドメインと次のJQLステートメントを使用してエンドポイントURLを構築します。このクエリは、ログインしているユーザーに対して「進行中」または「To do」のステータスを持つ課題をフィルターし、ステータス順に並べます。

const jiraDomain = process.env.JIRA_DOMAIN;
const email= process.env.JIRA_EMAIL;

const jql = "status%20in%20(%22In%20progress%22%2C%20%22To%20do%22)%20OR%20assignee%20%3D%20currentUser()%20order%20by%20status";
 
const apiUrl = `https://${jiraDomain}/rest/api/3/search?jql=${jql}`;

ルートを作成する前に、index.jsファイルにAxiosもインポートします。

const axios = require("axios")

これで、Jira APIにGETリクエストを行い、課題を返すルートを作成できます。index.jsに次のコードを追加します。

app.get('/issues/all', async (req, res) => {
  })

axios.getメソッドを使用してJira REST APIにGETリクエストを行います。JiraのメールとAPIトークンをbase64エンコードしてAuthorization ヘッダーを作成します。

const response = await axios.get(apiUrl, {
        headers: {
        Authorization: `Basic ${Buffer.from(
          `${email}:${JIRA_API_TOKEN}`
        ).toString("base64")}`,
        Accept: "application/json",
      },
    });

Jira APIからの応答を待ち、変数に保存します。レスポンスはissuesと呼ばれるプロパティを含み、課題オブジェクトの配列を保持します。

const data = await response.json();
const { issues } = data;

次に、issues 配列を繰り返し処理し、ToDo項目に関する関連情報のみを抽出し、JSONレスポンスで返します。

let cleanedIssues = [];
issues.forEach((issue) => {
      const issueData = {
        id: issue.id,
        projectName: issue.fields.project.name,
        status: issue.fields.status.name,
        deadline: issue.fields.duedate,
      };
      cleanedIssues.push(issueData);
});
res.status(200).json({ issues: cleanedIssues });

http://localhost:3000/issues/allにリクエストすると、課題を含むJSONオブジェクトを受け取ることになります。

curl localhost:3000/issues/all

さらに、SendGridのようなプロバイダとcronジョブを使用して、割り当てられたタスクを含むメールを毎日送信することもできます。

KinstaでNode.jsアプリケーションをホストする

Kinstaでアプリケーションをホストする前に、バックエンドとフロントエンドを異なるドメインでホストしているため、access-control-allow-originエラーが発生しないように、Cross-Origin Resource Sharing (CORS) を有効にします。これを行うには次の説明に従ってください。

  1. ターミナルで次のコマンドを実行して、cors npmパッケージをインストールします。
    npm install cors
  2. 次に、index.jsでパッケージをインポートします。
    const cors = require('cors')
  3. 次に、CORSをミドルウェアとして設定し、すべての受信リクエストに対して有効にします。index.jsファイルの先頭に以下のコードを追加してください。
    app.use(cors());

    これで、CORSエラーに遭遇することなく、異なるドメインからサーバーにHTTPリクエストを送信できるようになります。

次に、好みのGitサービス(BitbucketGitHub、またはGitLab)にコードをプッシュし、以下の手順に従ってください。

  1. ログインするか、アカウントを作成して、MyKinstaにログイン
  2. お使いのGitサービスでKinstaを認証
  3. 左サイドバーの「アプリケーション」をクリックし、「アプリケーションを追加」をクリック
  4. デプロイしたいリポジトリとブランチを選択
  5. アプリに一意の名前を割り当て「データセンターの所在地」を選択
  6. 環境変数を追加(Kinstaが自動で処理するため、環境変数としてPORTを追加する必要はありません。「ランタイムで利用可」と「ビルドプロセスで利用可」にチェックを入れます)

    環境変数のキーと値のペアを追加するフォーム
    Kinstaアプリの環境変数

  7. その他の情報を確認し(デフォルト値のままで構いません)、「アプリケーションを作成」をクリック

これでサーバーがKinstaに正常にデプロイされました。左側のメニューで、「ドメイン」をクリックし、プライマリドメインをコピーします。これがサーバーのURLエンドポイントです。

課題を表示するReactアプリケーションの構築

次に、Reactを使用してアプリのフロントエンドを構築し、CSSを使用してスタイルを設定します。以下の手順に従って、ViteでReactプロジェクトを構築していきます。

  1. jira-todoという名前のReactプロジェクトを作成します。
    npx create-vite jira-todo --template react
  2. プロジェクトディレクトリに移動し、必要な依存関係をインストールします。
    npm install
  3. 開発サーバーを起動します。
    npm run dev

サーバーから課題を取得

  1. App.jsxの内容を消去し、以下のコードを追加してください。
function App() {

  return (
    <div className="App">
      <h1>What's on my list today?</h1>
      {/* 課題を表示 */}

   </div>
 );
}

export default App;
  1. 課題の取得を開始する前に、KinstaからのサーバーURLをアプリのフォルダのルートにある.envファイルに保存します。
VITE_SERVER_BASE_URL="your-hosted-url"
  1. App.jsxファイルの先頭に次の行を追加して、URLを取得します。
const SERVER_BASE_URL=import.meta.env.VITE_SERVER_BASE_URL
  1. コンポーネントで、fetchDataという名前の非同期関数を作成し、Expressサーバーの/issues/allエンドポイントにGETリクエストを行います。レスポンスを受信したら、それをJSONとして解析し、dataという名前のstate値にデータを格納します。
import { useCallback, useEffect, useState } from "react";

function App() {
  const SERVER_BASE_URL=import.meta.env.VITE_SERVER_BASE_URL

  const [data, setData] = useState([]);
  const fetchData = useCallback(async () => {
    try {
      const response = await fetch(`${SERVER_BASE_URL}/issues/all`);
      if (!response.ok) {
        throw new Error('Network response was not ok');
     }
      const data = await response.json();
      	setData(data.issues);
    } catch (error) {
      console.error('Error fetching data:', error);
  }
     },[SERVER_BASE_URL]);

  useEffect(() => {
    // コンポーネントのマウント時にデータを取得
    fetchData();
     },[fetchData]);

  return (
    <div className="App">
        <h1>What's on my list today?</h1>
      
    </div>
  );
}

export default App;

useEffectフックを使用して、コンポーネントのマウント時にfetchData関数を実行することに注意してください。

ブラウザでJiraから課題をレンダリングする

  1. 続いては、コンポーネントのreturnステートメントを修正して、課題を繰り返し処理し、ブラウザに一覧表示します。
return (
  <div>
    <h1>What's on my list today?</h1>
    <section>
      	{data && data.map(issue => {
      	return <div className="issues" key={issue.id}>
        <div>
         <div>{issue.summary}</div>
          <small>{issue.deadline}</small>
        </div>
        <div>
          <div> className="status">{issue.status}</div>
        </div>
      </div>
    })}
    </section>
  </div>
);
  1. このアプリケーションのスタイルを調整するには、App.cssに以下のCSSコードを追加します。
h1 {
    text-align: center;
  font-size: 1.6rem;
  margin-top: 1rem;
}
section {
  display: flex;
  flex-direction: column;
 justify-content: center;
  align-items: center;
  margin-top: 2rem;
 }

 .issues {
  display: flex;
  min-width: 350px;
  justify-content: space-between;
  padding: 1rem;
  background-color: #eee;
  margin-bottom: 1rem;
}

 small {
  color: gray;
}

.status-btn {
  padding: 4px;
  border: 1px solid #000;
  border-radius: 5px;
}
  1. そして、スタイルを適用するために、index.jsApp.cssをインポートします。
import './App.css'

これで、アプリケーションを起動すると、あなたに割り当てられたタスクの一覧とステータス、期限がブラウザに表示されます。

A screenshot of the React application page
ユーザーに割り当てられたJiraの課題一覧

KinstaにReactアプリケーションをデプロイする

Kinstaの静的サイトホスティングを使用してアプリケーションをデプロイします。Kinstaの静的サイトホスティングを使うことで、静的ファイルをデプロイし素早くコンテンツの配信を開始することができます。

ソースコードをプッシュするためにGitHubにリポジトリを作成します。リポジトリの準備ができたら、以下の手順に従って静的サイトをKinstaにデプロイしましょう。

  1. アカウントを作成するかMyKinstaにログイン
  2. GitサービスでKinstaを認証
  3. 左サイドバーの「静的サイト」をクリックし「サイトを追加」をクリック
  4. デプロイしたいリポジトリとブランチを選択
  5. サイトに一意の名前を割り当てる
  6. MyKinstaのシステムがReactプロジェクトのビルド設定を自動で検出(以下の設定が入力されます)
    • ビルドコマンドnpm run build
    • Nodeのバージョン18.16.0
    • 公開ディレクトリdist
  1. VITE_SERVER_BASE_URLを使用してサーバーのURLを環境変数として追加
  2. 最後に「サイトを作成」をクリック

これで完了です。数秒でサイトのデプロイが完成しサイトのリンクが表示されます。サイトのドメインに移動すると、Jiraの課題一覧が表示されます。必要であれば、独自ドメインSSL証明書を後から追加可能です。

静的サイトホスティングの代わりとして、Kinstaのアプリケーションホスティングで静的サイトをデプロイすることもできます。これには、より高いレベルでのスケーラビリティ、Dockerfileを使用したデプロイメントのカスタマイズ、リアルタイムと過去のデータを網羅する包括的な分析などが付帯します。

まとめ

今回の記事では、Jira REST APIを使用して割り当てられたJiraの課題を取得するExpressアプリを構築する方法をご紹介しました。さらに、ReactフロントエンドアプリケーションをExpressアプリケーションに接続し、その課題をブラウザに表示しました。

このアプリは Jira REST APIで実現できることの初歩的なデモンストレーションとしてお考えください。タスクを完了としてマークしたり、高度なフィルタリングを実行したり、その他多くの機能でアプリを拡張することができます。

また、Kinstaでは、様々なサービスを使用して、サーバーとサイトの両方を1つのコントロールパネルで管理することができます。Kinstaの堅牢かつ柔軟なウェブホスティングをアプリケーションをはじめとするあらゆる用途にご活用ください。

Jeremy Holcombe Kinsta

Kinstaのコンテンツ&マーケティングエディター、WordPress開発者、コンテンツライター。WordPress以外の趣味は、ビーチでのんびりすること、ゴルフ、映画。高身長が特徴。