telegram-bot-ruby 1.0.0.pre → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6149f85b75abd46b546aac32fbe88da43e4a414bcaabb6ea05d213681d136460
4
- data.tar.gz: 88ae56d90f1e50883034d5433d3636f2feddc2ec31826466de31e23d61e2edfa
3
+ metadata.gz: 849ef276ecc1cfd4531ccd49474ca72e21e6a737f4ee49af374fd0f2cb7a6368
4
+ data.tar.gz: 8d451387892328aff6a1205f0b31b9221a07319c0b8d927c655d40283d2efc09
5
5
  SHA512:
6
- metadata.gz: c44671c55c2dcc30b15aef63d02351775a69ae2e73ed738e74ea97c469217b17f4e0581e5300dc4280b1dda36ce1ed4d2191ee9d824491935aaa09f1e1fcefbf
7
- data.tar.gz: e7c37c40f7f2dc9d86618a18b8e17e91a75f03632c60a8e075b78ce890d7c093501f3a4366b583b9cd3b85715bd06468cedc1472f5a153565ca132e5c97fe8d1
6
+ metadata.gz: ef343c2f15ee929777e6f03b5cc2e9af8f593e49a15bb751301476996bff8bcc3c79b99c962c5e865a379f23ddf8d505b0fabe22a3033a6e950a703ea54a9fa3
7
+ data.tar.gz: a9add629f338919e2584cccb8c7b206eaef726df39021ac0f9b42e26e7cf2c1cb65a28735e0010c3f390aee0f90f29fcb3a5d2c1981f0b8ba4829d55b14fd421
@@ -13,7 +13,7 @@ jobs:
13
13
  matrix:
14
14
  ruby:
15
15
  - 2.7
16
- - 3.1
16
+ - 3.2
17
17
  steps:
18
18
  - name: Checkout
19
19
  uses: actions/checkout@v3
@@ -31,7 +31,7 @@ jobs:
31
31
  matrix:
32
32
  ruby:
33
33
  - 2.7
34
- - 3.1
34
+ - 3.2
35
35
  env:
36
36
  BOT_API_ENV: test
37
37
  BOT_API_TOKEN: ${{ secrets.BOT_API_TOKEN }}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0
4
+
5
+ - Replace [virtus](https://github.com/solnic/virtus) with [dry-struct](https://github.com/dry-rb/dry-struct)
6
+ - Use [zeitwerk](https://github.com/fxn/zeitwerk) for code loading
7
+ - Implement [Bot API 6.4](https://core.telegram.org/bots/api#december-30-2022)
8
+ - Implement [Bot API 6.5](https://core.telegram.org/bots/api#february-3-2023)
9
+
3
10
  ## 0.23.0
4
11
 
5
12
  - Rename `Telegram::Bot.configuration` options:
data/Gemfile CHANGED
@@ -3,3 +3,12 @@
3
3
  source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
+
7
+ gem 'dotenv', '~> 2.8'
8
+ gem 'nokogiri', '~> 1.13'
9
+ gem 'pry'
10
+ gem 'rake', '~> 13.0'
11
+ gem 'rspec', '~> 3.4'
12
+ gem 'rubocop', '~> 1.27'
13
+ gem 'rubocop-rake'
14
+ gem 'rubocop-rspec', '~> 2.10'
data/README.md CHANGED
@@ -7,6 +7,21 @@ Ruby wrapper for [Telegram's Bot API](https://core.telegram.org/bots/api).
7
7
  [![Maintainability](https://api.codeclimate.com/v1/badges/7e61fbf5bec86e118fb1/maintainability)](https://codeclimate.com/github/atipugin/telegram-bot-ruby/maintainability)
8
8
  [![Say Thanks!](https://img.shields.io/badge/Say%20Thanks!-🦉-1EAEDB.svg)](https://saythanks.io/to/atipugin)
9
9
 
10
+ ## 🚧 Upgrading to 1.0
11
+
12
+ Since v1.0 telegram-bot-ruby uses [dry-struct](https://github.com/dry-rb/dry-struct) instead of [virtus](https://github.com/solnic/virtus). This means that type objects are now immutable and you can't change them after initialization:
13
+
14
+ ```ruby
15
+ # This won't work
16
+ kb = Telegram::Bot::Types::ReplyKeyboardRemove.new
17
+ kb.remove_keyboard = true
18
+
19
+ # You have to set attributes in constructor instead
20
+ kb = Telegram::Bot::Types::ReplyKeyboardRemove.new(remove_keyboard: true)
21
+ ```
22
+
23
+ Please make sure it doesn't break your existing code before upgrading to 1.0.
24
+
10
25
  ## Installation
11
26
 
12
27
  Add following line to your Gemfile:
data/Rakefile CHANGED
@@ -54,7 +54,7 @@ task :dump_type_attributes do
54
54
 
55
55
  # Write everything to fixture file
56
56
  File.write(
57
- File.expand_path('spec/fixtures/type_attributes.yml', __dir__),
57
+ File.expand_path('spec/support/type_attributes.yml', __dir__),
58
58
  result.to_yaml
59
59
  )
60
60
  end
@@ -26,7 +26,9 @@ module Telegram
26
26
  approveChatJoinRequest declineChatJoinRequest banChatSenderChat
27
27
  unbanChatSenderChat answerWebAppQuery setChatMenuButton
28
28
  getChatMenuButton setMyDefaultAdministratorRights
29
- getMyDefaultAdministratorRights createInvoiceLink
29
+ getMyDefaultAdministratorRights createInvoiceLink editGeneralForumTopic
30
+ closeGeneralForumTopic reopenGeneralForumTopic hideGeneralForumTopic
31
+ unhideGeneralForumTopic
30
32
  ].freeze
31
33
 
32
34
  attr_reader :token, :url, :environment
@@ -25,6 +25,8 @@ module Telegram
25
25
  attribute? :permissions, ChatPermissions
26
26
  attribute? :slow_mode_delay, Types::Integer
27
27
  attribute? :message_auto_delete_time, Types::Integer
28
+ attribute? :has_aggressive_anti_spam_enabled, Types::Bool
29
+ attribute? :has_hidden_members, Types::Bool
28
30
  attribute? :has_protected_content, Types::Bool
29
31
  attribute? :sticker_set_name, Types::String
30
32
  attribute? :can_set_sticker_set, Types::Bool
@@ -6,6 +6,7 @@ module Telegram
6
6
  class ChatJoinRequest < Base
7
7
  attribute :chat, Chat
8
8
  attribute :from, User
9
+ attribute :user_chat_id, Types::Integer
9
10
  attribute :date, Types::Integer
10
11
  attribute? :bio, Types::String
11
12
  attribute? :invite_link, ChatInviteLink
@@ -7,15 +7,20 @@ module Telegram
7
7
  attribute :status, Types::String
8
8
  attribute :user, User
9
9
  attribute :is_member, Types::Bool
10
- attribute :can_change_info, Types::Bool
11
- attribute :can_invite_users, Types::Bool
12
- attribute :can_pin_messages, Types::Bool
13
- attribute :can_manage_topics, Types::Bool
14
10
  attribute :can_send_messages, Types::Bool
15
- attribute :can_send_media_messages, Types::Bool
11
+ attribute :can_send_audios, Types::Bool
12
+ attribute :can_send_documents, Types::Bool
13
+ attribute :can_send_photos, Types::Bool
14
+ attribute :can_send_videos, Types::Bool
15
+ attribute :can_send_video_notes, Types::Bool
16
+ attribute :can_send_voice_notes, Types::Bool
16
17
  attribute :can_send_polls, Types::Bool
17
18
  attribute :can_send_other_messages, Types::Bool
18
19
  attribute :can_add_web_page_previews, Types::Bool
20
+ attribute :can_change_info, Types::Bool
21
+ attribute :can_invite_users, Types::Bool
22
+ attribute :can_pin_messages, Types::Bool
23
+ attribute :can_manage_topics, Types::Bool
19
24
  attribute :until_date, Types::Integer
20
25
  end
21
26
  end
@@ -5,7 +5,12 @@ module Telegram
5
5
  module Types
6
6
  class ChatPermissions < Base
7
7
  attribute? :can_send_messages, Types::Bool
8
- attribute? :can_send_media_messages, Types::Bool
8
+ attribute? :can_send_audios, Types::Bool
9
+ attribute? :can_send_documents, Types::Bool
10
+ attribute? :can_send_photos, Types::Bool
11
+ attribute? :can_send_videos, Types::Bool
12
+ attribute? :can_send_video_notes, Types::Bool
13
+ attribute? :can_send_voice_notes, Types::Bool
9
14
  attribute? :can_send_polls, Types::Bool
10
15
  attribute? :can_send_other_messages, Types::Bool
11
16
  attribute? :can_add_web_page_previews, Types::Bool
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ module Types
6
+ class ChatShared < Base
7
+ attribute :request_id, Types::Integer
8
+ attribute :chat_id, Types::Integer
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ module Types
6
+ class ForumTopicEdited < Base
7
+ attribute? :name, Types::String
8
+ attribute? :icon_custom_emoji_id, Types::String
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ module Types
6
+ class GeneralForumTopicHidden < Base
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ module Types
6
+ class GeneralForumTopicUnhidden < Base
7
+ end
8
+ end
9
+ end
10
+ end
@@ -13,6 +13,7 @@ module Telegram
13
13
  attribute? :width, Types::Integer
14
14
  attribute? :height, Types::Integer
15
15
  attribute? :duration, Types::Integer
16
+ attribute? :has_spoiler, Types::Bool
16
17
  end
17
18
  end
18
19
  end
@@ -9,6 +9,7 @@ module Telegram
9
9
  attribute? :caption, Types::String
10
10
  attribute? :parse_mode, Types::String
11
11
  attribute? :caption_entities, Types::Array.of(MessageEntity)
12
+ attribute? :has_spoiler, Types::Bool
12
13
  end
13
14
  end
14
15
  end
@@ -14,6 +14,7 @@ module Telegram
14
14
  attribute? :height, Types::Integer
15
15
  attribute? :duration, Types::Integer
16
16
  attribute? :supports_streaming, Types::Bool
17
+ attribute? :has_spoiler, Types::Bool
17
18
  end
18
19
  end
19
20
  end
@@ -5,6 +5,8 @@ module Telegram
5
5
  module Types
6
6
  class KeyboardButton < Base
7
7
  attribute :text, Types::String
8
+ attribute? :request_user, KeyboardButtonRequestUser
9
+ attribute? :request_chat, KeyboardButtonRequestChat
8
10
  attribute? :request_contact, Types::Bool
9
11
  attribute? :request_location, Types::Bool
10
12
  attribute? :request_poll, KeyboardButtonPollType
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ module Types
6
+ class KeyboardButtonRequestChat < Base
7
+ attribute :request_id, Types::Integer
8
+ attribute :chat_is_channel, Types::Bool
9
+ attribute? :chat_is_forum, Types::Bool
10
+ attribute? :chat_has_username, Types::Bool
11
+ attribute? :chat_is_created, Types::Bool
12
+ attribute? :user_administrator_rights, ChatAdministratorRights
13
+ attribute? :bot_administrator_rights, ChatAdministratorRights
14
+ attribute? :bot_is_member, Types::Bool
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ module Types
6
+ class KeyboardButtonRequestUser < Base
7
+ attribute :request_id, Types::Integer
8
+ attribute? :user_is_bot, Types::Bool
9
+ attribute? :user_is_premium, Types::Bool
10
+ end
11
+ end
12
+ end
13
+ end
@@ -36,6 +36,7 @@ module Telegram
36
36
  attribute? :voice, Voice
37
37
  attribute? :caption, Types::String
38
38
  attribute? :caption_entities, Types::Array.of(MessageEntity)
39
+ attribute? :has_media_spoiler, Types::Bool
39
40
  attribute? :contact, Contact
40
41
  attribute? :dice, Dice
41
42
  attribute? :game, Game
@@ -56,12 +57,18 @@ module Telegram
56
57
  attribute? :pinned_message, Message
57
58
  attribute? :invoice, Invoice
58
59
  attribute? :successful_payment, SuccessfulPayment
60
+ attribute? :user_shared, UserShared
61
+ attribute? :chat_shared, ChatShared
59
62
  attribute? :connected_website, Types::String
63
+ attribute? :write_access_allowed, WriteAccessAllowed
60
64
  attribute? :passport_data, PassportData
61
65
  attribute? :proximity_alert_triggered, ProximityAlertTriggered
62
66
  attribute? :forum_topic_created, ForumTopicCreated
67
+ attribute? :forum_topic_edited, ForumTopicEdited
63
68
  attribute? :forum_topic_closed, ForumTopicClosed
64
69
  attribute? :forum_topic_reopened, ForumTopicReopened
70
+ attribute? :general_forum_topic_hidden, GeneralForumTopicHidden
71
+ attribute? :general_forum_topic_unhidden, GeneralForumTopicUnhidden
65
72
  attribute? :video_chat_scheduled, VideoChatScheduled
66
73
  attribute? :video_chat_started, VideoChatStarted
67
74
  attribute? :video_chat_ended, VideoChatEnded
@@ -5,6 +5,7 @@ module Telegram
5
5
  module Types
6
6
  class ReplyKeyboardMarkup < Base
7
7
  attribute :keyboard, Types::Array.of(Types::Array.of(KeyboardButton))
8
+ attribute? :is_persistent, Types::Bool.default(false)
8
9
  attribute? :resize_keyboard, Types::Bool.default(false)
9
10
  attribute? :one_time_keyboard, Types::Bool.default(false)
10
11
  attribute? :input_field_placeholder, Types::String
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ module Types
6
+ class UserShared < Base
7
+ attribute :request_id, Types::Integer
8
+ attribute :user_id, Types::Integer
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ module Types
6
+ class WriteAccessAllowed < Base
7
+ end
8
+ end
9
+ end
10
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Telegram
4
4
  module Bot
5
- VERSION = '1.0.0.pre'
5
+ VERSION = '1.0.0'
6
6
  end
7
7
  end
@@ -26,13 +26,4 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency 'faraday', '~> 2.0'
27
27
  spec.add_dependency 'faraday-multipart', '~> 1.0'
28
28
  spec.add_dependency 'zeitwerk', '~> 2.6'
29
-
30
- spec.add_development_dependency 'dotenv', '~> 2.8'
31
- spec.add_development_dependency 'nokogiri', '~> 1.13'
32
- spec.add_development_dependency 'pry'
33
- spec.add_development_dependency 'rake', '~> 13.0'
34
- spec.add_development_dependency 'rspec', '~> 3.4'
35
- spec.add_development_dependency 'rubocop', '~> 1.27'
36
- spec.add_development_dependency 'rubocop-rake'
37
- spec.add_development_dependency 'rubocop-rspec', '~> 2.10'
38
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: telegram-bot-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Tipugin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-02 00:00:00.000000000 Z
11
+ date: 2023-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-struct
@@ -66,118 +66,6 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.6'
69
- - !ruby/object:Gem::Dependency
70
- name: dotenv
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '2.8'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '2.8'
83
- - !ruby/object:Gem::Dependency
84
- name: nokogiri
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '1.13'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '1.13'
97
- - !ruby/object:Gem::Dependency
98
- name: pry
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: rake
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '13.0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '13.0'
125
- - !ruby/object:Gem::Dependency
126
- name: rspec
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '3.4'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '3.4'
139
- - !ruby/object:Gem::Dependency
140
- name: rubocop
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '1.27'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '1.27'
153
- - !ruby/object:Gem::Dependency
154
- name: rubocop-rake
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
- - !ruby/object:Gem::Dependency
168
- name: rubocop-rspec
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - "~>"
172
- - !ruby/object:Gem::Version
173
- version: '2.10'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: '2.10'
181
69
  description:
182
70
  email:
183
71
  - atipugin@gmail.com
@@ -234,6 +122,7 @@ files:
234
122
  - lib/telegram/bot/types/chat_member_updated.rb
235
123
  - lib/telegram/bot/types/chat_permissions.rb
236
124
  - lib/telegram/bot/types/chat_photo.rb
125
+ - lib/telegram/bot/types/chat_shared.rb
237
126
  - lib/telegram/bot/types/chosen_inline_result.rb
238
127
  - lib/telegram/bot/types/compactable.rb
239
128
  - lib/telegram/bot/types/contact.rb
@@ -246,9 +135,12 @@ files:
246
135
  - lib/telegram/bot/types/forum_topic.rb
247
136
  - lib/telegram/bot/types/forum_topic_closed.rb
248
137
  - lib/telegram/bot/types/forum_topic_created.rb
138
+ - lib/telegram/bot/types/forum_topic_edited.rb
249
139
  - lib/telegram/bot/types/forum_topic_reopened.rb
250
140
  - lib/telegram/bot/types/game.rb
251
141
  - lib/telegram/bot/types/game_high_score.rb
142
+ - lib/telegram/bot/types/general_forum_topic_hidden.rb
143
+ - lib/telegram/bot/types/general_forum_topic_unhidden.rb
252
144
  - lib/telegram/bot/types/inline_keyboard_button.rb
253
145
  - lib/telegram/bot/types/inline_keyboard_markup.rb
254
146
  - lib/telegram/bot/types/inline_query.rb
@@ -286,6 +178,8 @@ files:
286
178
  - lib/telegram/bot/types/invoice.rb
287
179
  - lib/telegram/bot/types/keyboard_button.rb
288
180
  - lib/telegram/bot/types/keyboard_button_poll_type.rb
181
+ - lib/telegram/bot/types/keyboard_button_request_chat.rb
182
+ - lib/telegram/bot/types/keyboard_button_request_user.rb
289
183
  - lib/telegram/bot/types/labeled_price.rb
290
184
  - lib/telegram/bot/types/location.rb
291
185
  - lib/telegram/bot/types/login_url.rb
@@ -327,6 +221,7 @@ files:
327
221
  - lib/telegram/bot/types/update.rb
328
222
  - lib/telegram/bot/types/user.rb
329
223
  - lib/telegram/bot/types/user_profile_photos.rb
224
+ - lib/telegram/bot/types/user_shared.rb
330
225
  - lib/telegram/bot/types/venue.rb
331
226
  - lib/telegram/bot/types/video.rb
332
227
  - lib/telegram/bot/types/video_chat_ended.rb
@@ -338,6 +233,7 @@ files:
338
233
  - lib/telegram/bot/types/web_app_data.rb
339
234
  - lib/telegram/bot/types/web_app_info.rb
340
235
  - lib/telegram/bot/types/webhook_info.rb
236
+ - lib/telegram/bot/types/write_access_allowed.rb
341
237
  - lib/telegram/bot/version.rb
342
238
  - telegram-bot-ruby.gemspec
343
239
  homepage: https://github.com/atipugin/telegram-bot
@@ -355,11 +251,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
355
251
  version: '2.7'
356
252
  required_rubygems_version: !ruby/object:Gem::Requirement
357
253
  requirements:
358
- - - ">"
254
+ - - ">="
359
255
  - !ruby/object:Gem::Version
360
- version: 1.3.1
256
+ version: '0'
361
257
  requirements: []
362
- rubygems_version: 3.3.7
258
+ rubygems_version: 3.4.2
363
259
  signing_key:
364
260
  specification_version: 4
365
261
  summary: Ruby wrapper for Telegram's Bot API