twitter-api-v2
Twitter API v2.0 的轻量级跨平台封装库
1. 指南 ?
本库提供了在 Dart 和 Flutter 应用中最简单的方式来使用 Twitter API v2.0。
请给这个项目一些 ❤️ 并给它点星支持。
我们还提供 twitter_oauth2_pkce,用于在使用 Twitter API 时方便地进行 OAuth 2.0 PKCE 认证!
1.1. 特点 ✨
✅ Twitter API v2.0 的 **封装库**。
✅ **轻松集成** 到 Dart & Flutter 应用。
✅ 提供具有 **保证安全类型** 的响应对象。
✅ 支持 **所有 API 端点**。
✅ 支持 **所有请求参数和响应字段**。
✅ 支持 **高性能流式** 端点。
✅ 支持 **expansions** 和 **fields** 功能。
✅ **文档齐全** 且 **测试充分**。
✅ 支持强大的 **自动重试**。
1.2. 入门 ⚡
1.2.1. 安装库
使用 Dart
dart pub add twitter_api_v2
或使用 Flutter
flutter pub add twitter_api_v2
1.2.2. 导入
import 'package:twitter_api_v2/twitter_api_v2';
1.2.3. 实现
import 'dart:async';
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
//! You need to get keys and tokens at https://developer.twitter.com
final twitter = v2.TwitterApi(
//! Authentication with OAuth2.0 is the default.
//!
//! Note that to use endpoints that require certain user permissions,
//! such as Tweets and Likes, you need a token issued by OAuth2.0 PKCE.
//!
//! The easiest way to achieve authentication with OAuth 2.0 PKCE is
//! to use [twitter_oauth2_pkce](https://pub.dev/packages/twitter_oauth2_pkce)!
bearerToken: 'YOUR_TOKEN_HERE',
//! Or perhaps you would prefer to use the good old OAuth1.0a method
//! over the OAuth2.0 PKCE method. Then you can use the following code
//! to set the OAuth1.0a tokens.
//!
//! However, note that some endpoints cannot be used for OAuth 1.0a method
//! authentication.
oauthTokens: v2.OAuthTokens(
consumerKey: 'YOUR_CONSUMER_KEY_HERE',
consumerSecret: 'YOUR_CONSUMER_SECRET_HERE',
accessToken: 'YOUR_ACCESS_TOKEN_HERE',
accessTokenSecret: 'YOUR_ACCESS_TOKEN_SECRET_HERE',
),
//! Automatic retry is available when a TimeoutException occurs when
//! communicating with the API.
retryConfig: v2.RetryConfig.interval(
maxAttempts: 5,
intervalInSeconds: 3,
),
//! The default timeout is 10 seconds.
timeout: Duration(seconds: 20),
);
try {
// Get the authenticated user's profile.
final me = await twitter.usersService.lookupMe();
// Get the tweets associated with the search query.
final tweets = await twitter.tweetsService.searchRecent(
query: '#ElonMusk',
maxResults: 20,
// You can expand the search result.
expansions: [
v2.TweetExpansion.authorId,
v2.TweetExpansion.inReplyToUserId,
],
tweetFields: [
v2.TweetField.conversationId,
v2.TweetField.publicMetrics,
],
userFields: [
v2.UserField.location,
v2.UserField.verified,
v2.UserField.entities,
v2.UserField.publicMetrics,
],
);
await twitter.tweetsService.createLike(
userId: me.data.id,
tweetId: tweets.data.first.id,
);
// High-performance Volume Stream endpoint is available.
final volumeStream = await twitter.tweetsService.connectVolumeStream();
await for (final response in volumeStream.handleError(print)) {
print(response);
}
// Also high-performance Filtered Stream endpoint is available.
await twitter.tweetsService.createFilteringRules(
rules: [
v2.FilteringRuleParam(value: '#ElonMusk'),
v2.FilteringRuleParam(value: '#Tesla'),
v2.FilteringRuleParam(value: '#SpaceX'),
],
);
final filteredStream = await twitter.tweetsService.connectFilteredStream();
await for (final response in filteredStream.handleError(print)) {
print(response.data);
print(response.matchingRules);
}
} on TimeoutException catch (e) {
print(e);
} on v2.UnauthorizedException catch (e) {
print(e);
} on v2.RateLimitExceededException catch (e) {
print(e);
} on v2.TwitterException catch (e) {
print(e.response.headers);
print(e.body);
print(e);
}
}
1.3. 支持的端点 ?
1.3.1. 推文服务
1.3.1.1. 推文
| 端点 | 方法名 |
|---|---|
| POST /2/tweets | createTweet |
| DELETE /2/tweets/:id | destroyTweet |
1.3.1.2. 点赞
| 端点 | 方法名 |
|---|---|
| POST /2/users/:id/likes | createLike |
| DELETE /2/users/:id/likes/:tweet_id | destroyLike |
| GET /2/tweets/:id/liking_users | lookupLikingUsers |
| GET /2/users/:id/liked_tweets | lookupLikedTweets |
1.3.1.3. 转推
| 端点 | 方法名 |
|---|---|
| POST /2/users/:id/retweets | createRetweet |
| DELETE /2/users/:id/retweets/:source_tweet_id | destroyRetweet |
| GET /2/tweets/:id/retweeted_by | lookupRetweetedUsers |
1.3.1.4. 引用推文
| 端点 | 方法名 |
|---|---|
| GET /2/tweets/:id/quote_tweets | lookupQuoteTweets |
1.3.1.5. 搜索推文
| 端点 | 方法名 |
|---|---|
| GET /2/tweets/search/all | searchAll |
| GET /2/tweets/search/recent | searchRecent |
1.3.1.6. 查询推文
| 端点 | 方法名 |
|---|---|
| GET /2/tweets | lookupByIds |
| GET /2/tweets/:id | lookupById |
1.3.1.7. 推文计数
| 端点 | 方法名 |
|---|---|
| GET /2/tweets/counts/all | countAll |
| GET /2/tweets/counts/recent | countRecent |
1.3.1.8. 书签
| 端点 | 方法名 |
|---|---|
| POST /2/users/:id/bookmarks | createBookmark |
| DELETE /2/users/:id/bookmarks/:tweet_id | destroyBookmark |
| GET /2/users/:id/bookmarks | lookupBookmarks |
1.3.1.9. 时间线
| 端点 | 方法名 |
|---|---|
| GET /2/users/:id/mentions | lookupMentions |
| GET /2/users/:id/tweets | lookupTweets |
| GET /2/users/:id/timelines/reverse_chronological | lookupHomeTimeline |
1.3.1.10. 隐藏回复
| 端点 | 方法名 |
|---|---|
| PUT /2/tweets/:id/hidden | createHiddenReply |
| PUT /2/tweets/:id/hidden | destroyHiddenReply |
1.3.1.11. 容量流
| 端点 | 方法名 |
|---|---|
| GET /2/tweets/sample/stream | connectVolumeStream |
1.3.1.12. 过滤流
| 端点 | 方法名 |
|---|---|
| POST /2/tweets/search/stream/rules | createFilteringRules |
| GET /2/tweets/search/stream/rules | lookupFilteringRules |
| GET /2/tweets/search/stream | connectFilteredStream |
1.3.2. 用户服务
1.3.2.1. 关注
1.3.2.2. 查询用户
| 端点 | 方法名 |
|---|---|
| GET /2/users | lookupByIds |
| GET /2/users/:id | lookupById |
| GET /2/users/by | lookupByNames |
| GET /2/users/by/username/:username | lookupByName |
| GET /2/users/me | lookupMe |
1.3.2.3. 用户屏蔽
| 端点 | 方法名 |
|---|---|
| POST /2/users/:id/muting | createMute |
| DELETE /2/users/:source_user_id/muting/:target_user_id | destroyMute |
| GET /2/users/:id/muting | lookupMutingUsers |
1.3.2.4. 拉黑
| 端点 | 方法名 |
|---|---|
| POST /2/users/:id/blocking | createBlock |
| DELETE /2/users/:source_user_id/blocking/:target_user_id | destroyBlock |
| GET /2/users/:id/blocking | lookupBlockingUsers |
1.3.3. Spaces 服务
1.3.3.1. 搜索 Spaces
| 端点 | 方法名 |
|---|---|
| GET /2/spaces/search | search |
1.3.3.2. 查询 Spaces
| 端点 | 方法名 |
|---|---|
| GET /2/spaces | lookupByIds |
| GET /2/spaces/:id | lookupById |
| GET /2/spaces/:id/buyers | lookupBuyers |
| GET /2/spaces/:id/tweets | lookupTweets |
| GET /2/spaces/by/creator_ids | lookupByCreatorIds |
1.3.4. Lists 服务
1.3.4.1. 查询 Lists
| 端点 | 方法名 |
|---|---|
| GET /2/lists/:id | lookupById |
| GET /2/users/:id/owned_lists | lookupOwnedBy |
1.3.4.2. Pinning
| 端点 | 方法名 |
|---|---|
| POST /2/users/:id/pinned_lists | createPinnedList |
| DELETE /2/users/:id/pinned_lists/:list_id | destroyPinnedList |
| GET /2/users/:id/pinned_lists | lookupPinnedLists |
1.3.4.3. 推文查询
| 端点 | 方法名 |
|---|---|
| GET /2/lists/:id/tweets | lookupTweets |
1.3.4.4. List 管理
| 端点 | 方法名 |
|---|---|
| POST /2/lists | createPublicList |
| POST /2/lists | createPrivateList |
| DELETE /2/lists/:id | destroyList |
| PUT /2/lists/:id | updateListAsPublic |
| PUT /2/lists/:id | updateListAsPrivate |
1.3.4.5. Follows
1.3.4.6. Members
| 端点 | 方法名 |
|---|---|
| POST /2/lists/:id/members | createMember |
| DELETE /2/lists/:id/members/:user_id | destroyMember |
| GET /2/lists/:id/members | lookupMembers |
| GET /2/users/:id/list_memberships | lookupMemberships |
1.3.5. Compliance 服务
1.3.5.1. Batch Compliance
| 端点 | 方法名 |
|---|---|
| POST /2/compliance/jobs | createJob |
| GET /2/compliance/jobs | lookupJobs |
| GET /2/compliance/jobs/:id | lookupJob |
1.4. 技巧 ?
1.4.1. 方法名
twitter_api_v2 使用以下标准前缀,具体取决于端点特性。因此,找到与您想用的端点对应的方法非常容易!
| 前缀 | 描述 |
|---|---|
| lookup | 此前缀附加到引用推文、用户等的端点。 |
| search | 此前缀附加到执行广泛搜索的端点。 |
| connect | 此前缀附加到高性能流式端点。 |
| count | 此前缀附加到计算特定项的端点。 |
| create | 此前缀附加到执行创建状态的端点,例如 Tweet 和 Follow。 |
| destroy | 此前缀附加到执行销毁状态的端点,例如 Tweet 和 Follow。 |
| update | 此前缀附加到执行更新状态的端点。 |
1.4.2. 生成仅应用 Bearer Token
twitter_api_v2 提供生成/查找您的仅应用 Bearer Token 的实用程序。
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
final bearerToken = await v2.OAuthUtils.generateAppOnlyBearerToken(
consumerKey: 'YOUR_CONSUMER_KEY',
consumerSecret: 'YOUR_CONSUMER_SECRET',
);
print(bearerToken);
}
1.4.3. 请求中的 Null 参数
在此库中,请求时不需要的参数,即可选参数,被定义为可为空的。
但是,开发人员在使用此库发送请求时,无需意识到 Null 参数。
这意味着值为 Null 的参数在发送请求之前会被安全地删除并忽略。
例如,在以下请求中,指定为 Null 的参数将被忽略。
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
final twitter = v2.TwitterApi(bearerToken: 'YOUR_TOKEN_HERE');
await twitter.tweetsService.createTweet(
text: 'Hello, World!',
// These parameters are ignored at request because they are null.
mediaIds: null,
expansions: null,
);
}
1.4.4. 使用 expansions 展开对象字段
例如,可能出现数据仅包含 ID 的情况,而您想检索与该 ID 关联的数据对象。在这种情况下,称为 expansions 的 Twitter API v2.0 规范非常有用,并且本库支持该规范。
基本上,它可以在执行 GET 通信的端点中使用,例如 lookup 和 search 处理。某些字段也可能包含在 TwitterResponse 的 includes 属性中。
您可以如下使用 expansions
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
final twitter = v2.TwitterApi(bearerToken: 'YOUR_TOKEN_HERE');
try {
final tweets = await twitter.tweetsService.searchRecent(
query: '#ElonMusk',
// Specify fields you need!
expansions: [
v2.TweetExpansion.authorId,
v2.TweetExpansion.inReplyToUserId,
],
);
print(tweets);
} on v2.TwitterException catch (e) {
print(e);
}
}
您可以从 官方文档 查看有关 expansions 的更多详细信息。
1.4.5. 使用 fields 展开对象字段
Twitter API v2.0 支持一个非常有趣的规范,允许用户根据情况控制每个端点响应对象中包含的数据量。它称为 fields,并且本库支持此规范。
基本上,它可以在执行 GET 通信的端点中使用,例如 lookup 和 search 处理。某些字段也可能包含在 TwitterResponse 的 includes 字段中。
您可以如下使用 fields
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
final twitter = v2.TwitterApi(bearerToken: 'YOUR_TOKEN_HERE');
try {
final tweets = await twitter.tweetsService.searchRecent(
query: '#ElonMusk',
maxResults: 20,
expansions: v2.TweetExpansion.values,
tweetFields: [
v2.TweetField.conversationId,
v2.TweetField.publicMetrics,
],
userFields: [
v2.UserField.location,
v2.UserField.publicMetrics,
],
);
print(tweets);
} on v2.TwitterException catch (e) {
print(e);
}
}
笔记
某些字段必须与expansions结合使用。
您可以从 官方文档 查看有关 fields 的更多详细信息。
1.4.6. OAuth 2.0 Authorization Code Flow with PKCE
Twitter API v2.0 支持使用 OAuth 2.0 PKCE 的认证方法,它允许使用 Twitter API v2.0 的应用程序用户请求授权以获得最小必需的 scope 操作。
由于 OAuth2.0 PKCE 认证需要通过浏览器,twitter_api_v2 为与 CLI 应用程序的兼容性不提供此规范。相反,我们提供 twitter_oauth2_pkce,一个适用于 Flutter 应用的库。
twitter_oauth2_pkce 与 twitter_api_v2 100% 兼容,可以一起使用。您可以从以下链接查看更多详细信息。
此外,请参考以下结合了 twitter_api_v2 和 twitter_oauth2_pkce 的简单示例 Flutter 应用程序。
1.4.7. 更改超时时长
该库为所有 API 通信指定了默认 10 秒 的超时时间。
但是,有时您可能希望指定任意超时时长。如果存在这种需求,可以按如下方式指定任意超时时长。
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() {
final twitter = v2.TwitterApi(
bearerToken: 'YOUR_TOKEN_HERE',
//! The default timeout is 10 seconds.
timeout: Duration(seconds: 5),
);
}
1.4.8. 超时时重试
由于该库与外部系统通信的性质,由于不可避免的通信故障或请求发送到的服务器的临时崩溃,可能会发生超时。
当发生此类超时时,一个有效的对策通常是在一定间隔后再次发送请求。而 twitter_api_v2 提供了一个 **自动重试** 功能来解决这个问题。
twitter_api_v2 提供了两种自动重试方法。
- 按固定间隔重试
- 使用指数退避算法重试
1.4.8.1. 按固定间隔重试
按固定间隔重试很容易想象。例如,如果发生超时并且假设请求重试 3 次,等待 5 秒然后再次发送请求,则可以定义如下。
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
final twitter = v2.TwitterApi(
bearerToken: 'YOUR_TOKEN_HERE',
//! Add these lines.
retryConfig: v2.RetryConfig.interval(
maxAttempts: 3,
intervalInSeconds: 5,
),
);
}
1.4.8.2. 使用指数退避算法重试
尽管如上例所示,通过按固定间隔执行重试可以有效,但在请求发送到的服务器出现故障时,按固定间隔发送大量请求是应该避免的。即使网络或服务器已经宕机,重试过程也会通过增加负载来使情况更加糟糕。
这些问题的解决方案是为每次重试指数地增加间隔。此外,添加随机数可以防止服务器由于同时重试处理而导致的负载增加。
这是一种称为 Exponential Backoff 的算法,twitter_api_v2 支持允许轻松使用此算法的规范。可以通过如下定义 RetryConfig 来将指数退避算法应用于重试。
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
final twitter = v2.TwitterApi(
bearerToken: 'YOUR_TOKEN_HERE',
//! Add these lines.
retryConfig: v2.RetryConfig.exponentialBackOff(
maxAttempts: 3,
),
);
}
在上述实现中,间隔随着重试次数的增加而增加,这可以用公式 2 ^ retryCount 来表示。
1.4.8.3. 重试时执行操作
在重试时输出日志,并通过弹出窗口通知用户已执行重试会很有用。因此,twitter_api_v2 提供了可以在重试执行时执行任意处理的回调。
可以按如下方式实现。
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
final twitter = v2.TwitterApi(
bearerToken: 'YOUR_TOKEN_HERE',
retryConfig: v2.RetryConfig.interval(
maxAttempts: 3,
intervalInSeconds: 5,
//! Add this line.
onExecute: (context) => print('Retrying... ${context.retryCount} times.'),
),
);
}
传递给回调的 RetryContext 包含有关重试的信息。
1.4.9. 抛出异常
twitter_api_v2 提供了一个方便的异常对象,用于轻松处理来自 Twitter API v2.0 的异常响应和错误。
| 异常 | 描述 |
|---|---|
| TwitterException | 最基本的异常对象。例如,它可以用于查找已被删除的推文等。 |
| UnauthorizedException | 当使用指定的访问令牌进行身份验证失败时抛出。 |
| RateLimitExceededException | 当请求速率限制被超出时抛出。 |