Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/generate-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ jobs:
distribution: 'temurin'
java-version: 17
architecture: x64
- uses: ruby/setup-ruby@3ff19f5e2baf30647122352b96108b1fbe250c64 # v1.299.0
with:
ruby-version: '4.0'
- run: bundle install

# Generate codes
- name: Generate code
Expand Down
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ AllCops:
- 'lib/line/bot/v2/module_attach/**/*'
- 'lib/line/bot/v2/shop/**/*'
- 'lib/line/bot/v2/webhook/**/*'
- 'lib/line/bot/v2/line_bot_client.generated.rb'
- 'lib/line/bot/v2/line_bot_client.factory.generated.rb'
NewCops: disable

Gemspec/RequiredRubyVersion:
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Thus, you can't edit almost all code under `lib/line/bot/v2/<dir>.rb` and `sig/l

You need to edit the pebble template under [resources](generator/src/main/resources) instead.

After editing the templates, run `generate-code.py` to generate the code, and then commit all affected files.
After editing the templates, run `generate-code.py` to generate the code (including the unified client), and then commit all affected files.
If not, CI status will be red.

When you update code, be sure to check consistencies between `lib/**.rb` and `sig/**.rbs`.
Expand Down
43 changes: 32 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ You can code with type support in the corresponding IDE or editor.

### Basic Usage

The unified `Line::Bot::V2::LineBotClient` wraps all individual API clients into a single object.
You no longer need to create separate clients for MessagingApi, Insight, Liff, etc.

```ruby
# app.rb
require 'sinatra'
Expand All @@ -62,13 +65,7 @@ require 'line-bot-api'
set :environment, :production

def client
@client ||= Line::Bot::V2::MessagingApi::ApiClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN")
)
end

def blob_client
@blob_client ||= Line::Bot::V2::MessagingApi::ApiBlobClient.new(
@client ||= Line::Bot::V2::LineBotClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN")
)
end
Expand Down Expand Up @@ -109,9 +106,9 @@ post '/callback' do
)
client.reply_message(reply_message_request: request)
end

when Line::Bot::V2::Webhook::ImageMessageContent, Line::Bot::V2::Webhook::VideoMessageContent
response = blob_client.get_message_content(message_id: event.message.message_id)
response = client.get_message_content(message_id: event.message.message_id)
tf = Tempfile.open("content")
tf.write(response)
end
Expand All @@ -123,6 +120,10 @@ post '/callback' do
end
```

> **Note:** You can still use the individual clients (e.g. `Line::Bot::V2::MessagingApi::ApiClient`) if you prefer.
> For channel access token operations, use `Line::Bot::V2::ChannelAccessToken::ApiClient` directly.
> For module attach operations, use `Line::Bot::V2::ModuleAttach::ApiClient` directly.

### Main classes
You may use this classes to use LINE Messaging API features.

Expand All @@ -132,6 +133,26 @@ You may use this classes to use LINE Messaging API features.

### Clients

#### Unified Client (recommended)

`Line::Bot::V2::LineBotClient` wraps all API clients below (except ChannelAccessToken and ModuleAttach) into one object.
You only need a single `channel_access_token` to call any API.

```ruby
client = Line::Bot::V2::LineBotClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN")
)

# MessagingApi, Insight, Liff, ManageAudience, Module, Shop — all available:
client.push_message(push_message_request: request)
client.get_number_of_followers(date: '20240101')
client.get_message_content(message_id: '12345')
```

#### Individual Clients

You can also use the individual clients directly if you need finer control.

| Class(YARD documentation) | API EndPoint | LINE Developers |
|----------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
| [Line::Bot::V2::ChannelAccessToken::ApiClient](https://line.github.io/line-bot-sdk-ruby/Line/Bot/V2/ChannelAccessToken/ApiClient.html) | https://api.line.me/** (related to oauth) | https://developers.line.biz/en/reference/messaging-api/#channel-access-token |
Expand Down Expand Up @@ -173,7 +194,7 @@ require 'json'
require 'line-bot-api'

def client
@client ||= Line::Bot::V2::MessagingApi::ApiClient.new(
@client ||= Line::Bot::V2::LineBotClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
)
end
Expand Down Expand Up @@ -219,7 +240,7 @@ This is useful, for example, in migrating from v1 or building Flex Message.
**But this is not recommended because you lose type checking by RBS.**

```ruby
client = Line::Bot::V2::MessagingApi::ApiClient.new(
client = Line::Bot::V2::LineBotClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
)

Expand Down
6 changes: 3 additions & 3 deletions Steepfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ target :lib do
end

target :test do
unreferenced! # Skip type checking the `lib` code when types in `test` target is changed
unreferenced! # Skip type checking the `lib` code when types in test targets is changed
signature "sig/test" # Put RBS files for tests under `sig/test`
check "test" # Type check Ruby scripts under `test`
check "test", "type-test" # Type check Ruby scripts under `test` and `type-test`

configure_code_diagnostics(D::Ruby.lenient) # Weak type checking for test code
configure_code_diagnostics(D::Ruby.strict) # Keep integration type tests meaningful in CI

# library "pathname" # Standard libraries
end
18 changes: 3 additions & 15 deletions examples/v2/audience/app.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
require 'line-bot-api'

def client
@client ||= Line::Bot::V2::ManageAudience::ApiClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
)
end

def blob_client
@blob_client ||= Line::Bot::V2::ManageAudience::ApiBlobClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
)
end

def api_client
@api_client ||= Line::Bot::V2::MessagingApi::ApiClient.new(
@client ||= Line::Bot::V2::LineBotClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
)
end
Expand Down Expand Up @@ -71,7 +59,7 @@ def add_audience_by_ids(audience_group_id:)
def add_audience_by_file(audience_group_id:)
# TODO: replace with your user ID in audience.txt
File.open('audience.txt', 'r') do |f|
_body, status_code, _http_headers = blob_client.add_user_ids_to_audience_with_http_info(
_body, status_code, _http_headers = client.add_user_ids_to_audience_with_http_info(
audience_group_id: audience_group_id,
file: f
)
Expand Down Expand Up @@ -120,7 +108,7 @@ def push_narrowcast(audience_group_id:)
audience_group_id: audience_group_id,
)
)
_body, status_code, _http_headers = api_client.narrowcast_with_http_info(narrowcast_request: request)
_body, status_code, _http_headers = client.narrowcast_with_http_info(narrowcast_request: request)

if status_code == 202
puts '=== Push narrowcast successfully ==='
Expand Down
2 changes: 1 addition & 1 deletion examples/v2/echobot/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
set :app_base_url, ENV.fetch('APP_BASE_URL')

def client
@client ||= Line::Bot::V2::MessagingApi::ApiClient.new(
@client ||= Line::Bot::V2::LineBotClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN")
)
end
Expand Down
28 changes: 6 additions & 22 deletions examples/v2/kitchensink/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
QUICK_REPLY_ICON_URL = 'https://via.placeholder.com/64x64'

def client
@client ||= Line::Bot::V2::MessagingApi::ApiClient.new(
@client ||= Line::Bot::V2::LineBotClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
http_options: {
open_timeout: 5,
Expand All @@ -19,22 +19,6 @@ def client
)
end

def blob_client
@blob_client ||= Line::Bot::V2::MessagingApi::ApiBlobClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
http_options: {
open_timeout: 5,
read_timeout: 5
}
)
end

def insight_client
@insight_client ||= Line::Bot::V2::Insight::ApiClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
)
end

def parser
@parser ||= Line::Bot::V2::WebhookParser.new(channel_secret: ENV.fetch("LINE_CHANNEL_SECRET"))
end
Expand Down Expand Up @@ -136,7 +120,7 @@ def storeContent(message_id:, message_type:)
max_retries = 10

max_retries.times do |i|
body, status_code, _headers = blob_client.get_message_content_transcoding_by_message_id_with_http_info(
body, status_code, _headers = client.get_message_content_transcoding_by_message_id_with_http_info(
message_id: message_id
)

Expand Down Expand Up @@ -165,7 +149,7 @@ def storeContent(message_id:, message_type:)
end
end

content, _, headers = blob_client.get_message_content_with_http_info(message_id: message_id)
content, _, headers = client.get_message_content_with_http_info(message_id: message_id)
content_type = headers['content-type']
ext = case content_type
when 'image/jpeg' then 'jpg'
Expand Down Expand Up @@ -936,12 +920,12 @@ def rich_menu_request_b

create_rich_menu_a_response = client.create_rich_menu(rich_menu_request: rich_menu_request_a)
logger.info "Create rich menu A: #{create_rich_menu_a_response.rich_menu_id}"
a = blob_client.set_rich_menu_image(rich_menu_id: create_rich_menu_a_response.rich_menu_id, body: File.open('./richmenu/richmenu-a.png'))
a = client.set_rich_menu_image(rich_menu_id: create_rich_menu_a_response.rich_menu_id, body: File.open('./richmenu/richmenu-a.png'))
logger.info "Set rich menu image A: #{a}"

create_rich_menu_b_response = client.create_rich_menu(rich_menu_request: rich_menu_request_b)
logger.info "Create rich menu B: #{create_rich_menu_b_response.rich_menu_id}"
a = blob_client.set_rich_menu_image(rich_menu_id: create_rich_menu_b_response.rich_menu_id, body: File.open('./richmenu/richmenu-b.png'))
a = client.set_rich_menu_image(rich_menu_id: create_rich_menu_b_response.rich_menu_id, body: File.open('./richmenu/richmenu-b.png'))
logger.info "Set rich menu image B: #{a}"

client.set_default_rich_menu(rich_menu_id: create_rich_menu_a_response.rich_menu_id)
Expand Down Expand Up @@ -1057,7 +1041,7 @@ def rich_menu_request_b

when /\Astats\s+(?<request_id>.+)/
request_id = Regexp.last_match[:request_id]
stats = insight_client.get_message_event(request_id: request_id)
stats = client.get_message_event(request_id: request_id)

reply_text(event, "[STATS]\n#{stats}")

Expand Down
12 changes: 3 additions & 9 deletions examples/v2/rich_menu/app.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
require 'line-bot-api'

def client
@client ||= Line::Bot::V2::MessagingApi::ApiClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
)
end

def blob_client
@blob_client ||= Line::Bot::V2::MessagingApi::ApiBlobClient.new(
@client ||= Line::Bot::V2::LineBotClient.new(
channel_access_token: ENV.fetch("LINE_CHANNEL_ACCESS_TOKEN"),
)
end

def main
create_rich_menu_a_response = client.create_rich_menu(rich_menu_request: rich_menu_request_a)
puts "created: #{create_rich_menu_a_response.rich_menu_id}"
blob_client.set_rich_menu_image(rich_menu_id: create_rich_menu_a_response.rich_menu_id, body: File.open('./public/richmenu-a.png'))
client.set_rich_menu_image(rich_menu_id: create_rich_menu_a_response.rich_menu_id, body: File.open('./public/richmenu-a.png'))

create_rich_menu_b_response = client.create_rich_menu(rich_menu_request: rich_menu_request_b)
puts "created: #{create_rich_menu_b_response.rich_menu_id}"
blob_client.set_rich_menu_image(rich_menu_id: create_rich_menu_b_response.rich_menu_id, body: File.open('./public/richmenu-b.png'))
client.set_rich_menu_image(rich_menu_id: create_rich_menu_b_response.rich_menu_id, body: File.open('./public/richmenu-b.png'))

client.set_default_rich_menu(rich_menu_id: create_rich_menu_a_response.rich_menu_id)

Expand Down
5 changes: 5 additions & 0 deletions generate-code.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,18 @@ def generate_clients():
run_command("rm -rf lib/line/bot/v2/webhook/api")
run_command("rm -rf sig/line/bot/v2/webhook/api")

def generate_unified_client():
"""Generate the unified client that wraps all individual API clients."""
run_command('bundle exec ruby scripts/unified-client-generator/main.rb')

def main():
"""Main function to package and generate clients."""
os.chdir("generator")
run_command('mvn package -DskipTests=true')
os.chdir("..")

generate_clients()
generate_unified_client()

if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions lib/line/bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
require 'line/bot/v2/module_attach/core'
require 'line/bot/v2/shop/core'
require 'line/bot/v2/webhook/core'
require 'line/bot/v2/line_bot_client'
46 changes: 46 additions & 0 deletions lib/line/bot/v2/line_bot_client.factory.generated.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This file is autogenerated.
#
# Generated by scripts/unified-client-generator/main.rb
# Do not edit this file directly.

module Line
module Bot
module V2
class LineBotClient
private

def build_generated_delegates(
channel_access_token:,
api_base_url: nil,
data_api_base_url: nil,
http_options: {}
)
@insight = Line::Bot::V2::Insight::ApiClient.
new(base_url: api_base_url, channel_access_token: channel_access_token, http_options: http_options)

@liff = Line::Bot::V2::Liff::ApiClient.
new(base_url: api_base_url, channel_access_token: channel_access_token, http_options: http_options)

@manage_audience = Line::Bot::V2::ManageAudience::ApiClient.
new(base_url: api_base_url, channel_access_token: channel_access_token, http_options: http_options)

@manage_audience_blob = Line::Bot::V2::ManageAudience::ApiBlobClient.
new(base_url: data_api_base_url, channel_access_token: channel_access_token, http_options: http_options)

@messaging_api = Line::Bot::V2::MessagingApi::ApiClient.
new(base_url: api_base_url, channel_access_token: channel_access_token, http_options: http_options)

@messaging_api_blob = Line::Bot::V2::MessagingApi::ApiBlobClient.
new(base_url: data_api_base_url, channel_access_token: channel_access_token, http_options: http_options)

@line_module = Line::Bot::V2::Module::ApiClient.
new(base_url: api_base_url, channel_access_token: channel_access_token, http_options: http_options)

@shop = Line::Bot::V2::Shop::ApiClient.
new(base_url: api_base_url, channel_access_token: channel_access_token, http_options: http_options)
nil
end
end
end
end
end
Loading