34
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

個人開発エンジニア応援 - 個人開発の成果や知見を共有しよう!-

【個人開発】GraphQL API を叩いて毎朝電気代が届くLine Botを開発する【前編】

Last updated at Posted at 2023-10-17

はじめに

今回、私が使用している オクトパスエナジー がGraphQL APIを提供しているので
それを用いて毎朝電気代が届くLine Botを開発します。

今回は、Railsと外部API連携GraphQLの叩き方Line Messaging APIを利用していきます。
定期実行、デプロイ編について後編記事で書く予定です(まだ実装してない)

そもそもGraphQLって何?という方は下記の記事をご覧ください

使用技術

Rails(APIモード): 7.0.8
Ruby: 3.2.0
graphql 2.0.27
Line Messaging API

実装方針

1.Rails側からGraphQL叩いて電気代を取得出来るようにする
2.Line Messaging APIを利用して、取得した電気代情報をユーザーに送信する機能の実装 
-- 今回はここまで --
3.開発環境で定期実行用のタスクを作成する
4.本番環境で定期実行を行えるようにする

Rails側からGraphQL叩いて電気代を取得出来るようにする

オクトパスエナジーで電気代を取得するには以下の2ステップになります。

1-1.emailとパスワードをクエリ変数として,認証トークンの取得(mutation)
1-2.認証トークンを使用して、電気代情報の取得(query)

MutationとQueryの使い分け

基本的には下記の図解の使い分けになります。

  • RESTとはRepresentational State Transferの略でwebサービスの設計モデルのこと
  • SQLとはデータベース用のクエリ言語のこと
  • GraphQLとはAPIのクエリ言語のこと
Rest SQL GraphQL
データ取得 GET Select Query
データ追加 POST Create Mutation
データ更新 PATCH Update Mutation
データ削除 DELETE Delete Mutation

データの取得はQueryでそれ以外はMutationと考えると覚えやすいかも知れません(因みにイベント監視はSubscription)

事前準備

とその前に RailsアプリでGraphqlが使えるように以下のgemを追加してbundle installを行います。

Gemfile
gem 'graphql'
gem 'graphql-client'
gem 'dotenv-rails'

graphql-clientとは
GraphQLのクエリを宣言、作成、実行を行うRubyライブラリことです。

詳しくは以下を参照してください。

dotenv-railsとは
環境変数を管理するRubyライブラリのことです。
自信が作成した、アプリケーションの直下に.envファイルを作成することでシークレットキーやパスワードなど
ネットに公開させたくない情報を扱い、自動で読み込むことが可能です。

.env
OCTOPUS_EMAIL = "XXX@example.com"
OCTOPUS_PASSWORD = "passwordhogefuga"

のような形式で定義することができます。
呼び出す際は ENV["OCTOPUS_EMAIL"] のような形式で呼び出すことができます!

隠したいファイルですので .gitignoreを設定 することは忘れないようにしましょう。

詳しくは以下を参照してください。

1-1.emailとパスワードをクエリ変数として,認証トークンの取得

上記インストールを行った後に、トークンの取得のために以下のファイルを作成します。

今回、graphql-clientについて補足説明が少なかったのでコメントアウトで
説明しておきます。

lib/octopus_authentication_token.rb
require "graphql/client"
require "graphql/client/http"

class OctopusAuthenticationToken
  # http アダプターを設定
  HTTP = GraphQL::Client::HTTP.new("https://api.oejp-kraken.energy/v1/graphql/")

  # 上記を使用して、API サーバーから GraphQL Schema を取得
  Schema = GraphQL::Client.load_schema(HTTP)

  # 上記を使ってクライアント作成
  Client = GraphQL::Client.new(schema: Schema, execute: HTTP)

  # ログイントークンを作成する,mutationを定義
  LOGIN_QUERY = self::Client.parse <<~GRAPHQL
    mutation($input: ObtainJSONWebTokenInput!) {
      obtainKrakenToken(input: $input) {
        token
        refreshToken
      }
    }
  GRAPHQL

  def generate_token
    # mutationを実行してその実行結果をresultに格納する
    result = Client.query(LOGIN_QUERY, variables: {
      input: {
        email: ENV["OCTOPUS_EMAIL"],
        password: ENV["OCTOPUS_PASSWORD"],
      },
    })
    result.original_hash.dig("data", "obtainKrakenToken", "token")
  end
end

上記で、ログイントークンを取得するためのGraphQLクライアントの設定とクエリの定義と、
トークン作成用のメソッドを定義しております。

1-2.認証トークンを使用して、電気代情報の取得

さて、認証トークンを作成したと思うのでそのトークンを元に
電気代取得のためのHTTPクライアントを作成します。

lib/octopus_client.rb
require "graphql/client"
require "graphql/client/http"

module OctopusClient    
  HTTP = GraphQL::Client::HTTP.new("https://api.oejp-kraken.energy/v1/graphql/") do
    def headers(context)
      { "Authorization" => "#{OctopusAuthenticationToken.new.generate_token}" }
    end
  end

  Schema = GraphQL::Client.load_schema(HTTP)
  Client = GraphQL::Client.new(schema: Schema, execute: HTTP)
end

上記では,lib/octopus_authentication_token.rbで作成した
OctopusAuthenticationToken クラスのインスタンスメソッドを読んで
tokenを取得しヘッダーにセットし、Client作成を行っています。

そして,octopus_energy_bill/indexにアクセスをしたらAPIを叩くよう実装を行います。

app/controllers/octopus_energy_bill_controller.rb
class OctopusEnergyBillController < ApplicationController

  GetBillQUERY = OctopusClient::Client.parse <<~'GRAPHQL'
	query(
		$accountNumber: String!
		$fromDatetime: DateTime
		$toDatetime: DateTime
	) {
		account(accountNumber: $accountNumber) {
			properties {
				electricitySupplyPoints {
					agreements {
						validFrom
					}
					halfHourlyReadings(
						fromDatetime: $fromDatetime
						toDatetime: $toDatetime
					) {
						startAt
            endAt
						value
						costEstimate
						consumptionStep
						consumptionRateBand
					}
				}
			}
		}
	}
  GRAPHQL

  def index 
    result = OctopusClient::Client.query(GetBillQUERY, variables: {
      accountNumber: ENV['OCTOPUS_ACCOUNT_NUMBER'],
      fromDatetime: Date.yesterday.beginning_of_day.iso8601,
      toDatetime: Date.yesterday.end_of_day.iso8601
      })
    properties = result.original_hash.dig("data", "account", "properties")
    electricity_supply_points = properties.first["electricitySupplyPoints"]
    half_hourly_readings = electricity_supply_points.first["halfHourlyReadings"]
    @kwh = half_hourly_readings.pluck("value").map(&:to_f).sum
    @cost = half_hourly_readings.pluck("costEstimate").map(&:to_f).sum
    puts "#{Date.yesterday.strftime('%Y年%m月%d日')}#{@kwh.round(2)}kWh消費して#{@cost}円かかったよ" 
  end
end

routes.rb
+  resources :octopus_energy_bill, only: %i[index]

また、今回の実装にあたりissueを作成して実装したので参考にしたい方はどうぞ。

Line Messaging APIを利用して、取得した電気代情報をユーザーに送信する機能の実装

下記のgemを前の章同様にinstallしていきます。

Gemfile
gem 'line-bot-api'

Messaging API チャンネルを作成していきます。

上記の記事で詳しく説明されているので、当記事では省略します。

スクリーンショット 2023-10-17 1.10.21.png

上記のような形で、今回はオクトパスエナジーの非公式botを作成しました。

また、今回作成された チャネルシークレトLINE_CHANNEL_SECRETに、チャンネルアクセストークンLINE_CHANNEL_TOKEN.envファイルで定義します。

さて、チャネルシークレットチャネルアクセストークンを使用してクライアントを作成します。

lib/line_bot_client.rb
class LineBotClient
  def client 
    Line::Bot::Client.new { |config|
      config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
      config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
    }
  end
end

この記述によってLineBotClient.new.clientLine::Bot::Clientのインスタンスを作成出来るようになります。

さて、上記を使ってLINEを送ってみましょう!!

app/controllers/octopus_energy_bill_controller.rb
class OctopusEnergyBillController < ApplicationController

	GetBillQUERY = OctopusClient::Client.parse <<~'GRAPHQL'
		query(
			$accountNumber: String!
			$fromDatetime: DateTime
			$toDatetime: DateTime
		) {
			account(accountNumber: $accountNumber) {
				properties {
					electricitySupplyPoints {
						agreements {
							validFrom
						}
						halfHourlyReadings(
							fromDatetime: $fromDatetime
							toDatetime: $toDatetime
						) {
							startAt
							endAt
							value
							costEstimate
							consumptionStep
							consumptionRateBand
						}
					}
				}
			}
		}
  GRAPHQL

  def index 
    result = OctopusClient::Client.query(GetBillQUERY, variables: {
      accountNumber: ENV['OCTOPUS_ACCOUNT_NUMBER'],
      fromDatetime: Date.yesterday.beginning_of_day.iso8601,
      toDatetime: Date.yesterday.end_of_day.iso8601
      })

    properties = result.original_hash.dig("data", "account", "properties")
    electricity_supply_points = properties.first["electricitySupplyPoints"]
    half_hourly_readings = electricity_supply_points.first["halfHourlyReadings"]
    @kwh = half_hourly_readings.pluck("value").map(&:to_f).sum
    @cost = half_hourly_readings.pluck("costEstimate").map(&:to_f).sum
-   puts "#{Date.yesterday.strftime('%Y年%m月%d日')}#{@kwh.round(2)}kWh消費して#{@cost}円かかったよ"
+   text = "#{Date.yesterday.strftime('%Y年%m月%d日')}#{@kwh.round(2)}kWh消費して#{@cost}円かかったよ" 

+	message = {
+     type: 'text',
+     text: text
+    }
+    LineBotClient.new.client.broadcast(message)
  end
end

そして、/octopus_energy_billエンドポイントにアクセスすると、以下のようにLINEが送ることができます。

IMG_9781.png

以上で今回の目標物は完成です!!

最後に

いかがでしたでしょうか。
今回は、GraphQLとRails(APIモード)を使用して、電気代Line botを開発していきました。

次回はデプロイと定期実行を行なっていこうと思います🔥

最後まで読んで頂きありがとうございました!

後編記事

参考文献

34
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?