Skip to content

Commit

Permalink
Merge #605
Browse files Browse the repository at this point in the history
605: feat: fixed for the issue (#604) r=myConsciousness a=myConsciousness

# 1. Description

<!-- Provide a description of what this PR is doing.
If you're modifying existing behavior, describe the existing behavior, how this PR is changing it,
and what motivated the change. If this is a breaking change, specify explicitly which APIs have been
changed. -->

## 1.1. Checklist

<!-- Before you create this PR confirm that it meets all requirements listed below by checking the
relevant checkboxes (`[x]`). This will ensure a smooth and quick review process. -->

- [x] The title of my PR starts with a [Conventional Commit] prefix (`fix:`, `feat:`, `docs:` etc).
- [x] I have read the [Contributor Guide] and followed the process outlined for submitting PRs.
- [x] I have updated/added tests for ALL new/updated/fixed functionality.
- [x] I have updated/added relevant documentation in `docs` and added dartdoc comments with `///`.
- [x] I have updated/added relevant examples in `examples`.

## 1.2. Breaking Change

<!-- Does your PR require users to manually update their apps to accommodate your change?

If the PR is a breaking change this should be indicated with suffix "!"  (for example, `feat!:`, `fix!:`). See [Conventional Commit] for details.
-->

- [ ] Yes, this is a breaking change.
- [x] No, this is _not_ a breaking change.

## 1.3. Related Issues

<!-- Provide a list of issues related to this PR from the [issue database].
Indicate which of these issues are resolved or fixed by this PR, i.e. Fixes #xxxx* !-->

<!-- Links -->

[issue database]: https://github.com/twitter-dart/twitter-api-v2/issues
[contributor guide]: https://github.com/twitter-dart/twitter-api-v2/blob/main/CONTRIBUTING.md
[style guide]: https://github.com/twitter-dart/twitter-api-v2/blob/main/STYLEGUIDE.md
[conventional commit]: https://conventionalcommits.org


Co-authored-by: myConsciousness <[email protected]>
  • Loading branch information
bors[bot] and myConsciousness authored Dec 12, 2022
2 parents 4edbdad + fa1a867 commit e53e6ed
Show file tree
Hide file tree
Showing 11 changed files with 618 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- `ofExponentialBackOff`
- `ofExponentialBackOffAndJitter`
- For endpoints that can use both OAuth 2.0 and OAuth 1.0a authentication methods, the resolution of both has been improved. Starting with this version, OAuth 2.0 is the highest priority authentication method. For example, if OAuth 2.0 and OAuth 1.0a tokens are specified at the same time, the OAuth 2.0 client is always used for v2 endpoints. ([#596](https://github.com/twitter-dart/twitter-api-v2/issues/596))
- A utility has been added to this package to allow access token refresh. `OAuthUtils.refreshAccessToken` can be used to refresh access tokens issued by OAuth 2.0 PKCE. ([#604](https://github.com/twitter-dart/twitter-api-v2/issues/604))

## v4.6.1

Expand Down
84 changes: 56 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,21 @@
- [1.4.1. Method Names](#141-method-names)
- [1.4.2. Automatic REST Client Resolution](#142-automatic-rest-client-resolution)
- [1.4.3. Generate App-Only Bearer Token](#143-generate-app-only-bearer-token)
- [1.4.4. Null Parameter at Request](#144-null-parameter-at-request)
- [1.4.5. Expand Object Fields with `expansions`](#145-expand-object-fields-with-expansions)
- [1.4.6. Expand Object Fields with `fields`](#146-expand-object-fields-with-fields)
- [1.4.7. JSON Serialization and Deserialization](#147-json-serialization-and-deserialization)
- [1.4.8. OAuth 2.0 Authorization Code Flow with PKCE](#148-oauth-20-authorization-code-flow-with-pkce)
- [1.4.9. Change the Timeout Duration](#149-change-the-timeout-duration)
- [1.4.10. Automatic Retry](#1410-automatic-retry)
- [1.4.10.1. Exponential BackOff and Jitter](#14101-exponential-backoff-and-jitter)
- [1.4.10.2. Do Something on Retry](#14102-do-something-on-retry)
- [1.4.11. Meaning of the Returned Boolean](#1411-meaning-of-the-returned-boolean)
- [1.4.12. Thrown Exceptions](#1412-thrown-exceptions)
- [1.4.13. Upload Media](#1413-upload-media)
- [1.4.14. Check the Progress of Media Upload](#1414-check-the-progress-of-media-upload)
- [1.4.15. Generate Filtering Rules Safely and Easily](#1415-generate-filtering-rules-safely-and-easily)
- [1.4.4. Refresh Access Token](#144-refresh-access-token)
- [1.4.5. Null Parameter at Request](#145-null-parameter-at-request)
- [1.4.6. Expand Object Fields with `expansions`](#146-expand-object-fields-with-expansions)
- [1.4.7. Expand Object Fields with `fields`](#147-expand-object-fields-with-fields)
- [1.4.8. JSON Serialization and Deserialization](#148-json-serialization-and-deserialization)
- [1.4.9. OAuth 2.0 Authorization Code Flow with PKCE](#149-oauth-20-authorization-code-flow-with-pkce)
- [1.4.10. Change the Timeout Duration](#1410-change-the-timeout-duration)
- [1.4.11. Automatic Retry](#1411-automatic-retry)
- [1.4.11.1. Exponential BackOff and Jitter](#14111-exponential-backoff-and-jitter)
- [1.4.11.2. Do Something on Retry](#14112-do-something-on-retry)
- [1.4.12. Meaning of the Returned Boolean](#1412-meaning-of-the-returned-boolean)
- [1.4.13. Thrown Exceptions](#1413-thrown-exceptions)
- [1.4.14. Upload Media](#1414-upload-media)
- [1.4.15. Check the Progress of Media Upload](#1415-check-the-progress-of-media-upload)
- [1.4.16. Generate Filtering Rules Safely and Easily](#1416-generate-filtering-rules-safely-and-easily)
- [1.5. Contribution 🏆](#15-contribution-)
- [1.6. Contributors ✨](#16-contributors-)
- [1.7. Support ❤️](#17-support-️)
Expand Down Expand Up @@ -676,7 +677,34 @@ Future<void> main() async {
}
```

### 1.4.4. Null Parameter at Request
### 1.4.4. Refresh Access Token

The advantage of access tokens issued by **OAuth 2.0 PKCE** is not only security, but also the ability to determine user access permissions in detail. However, the lifespan of this access token is short, expiring in about 2 hours.

And then, the `refresh token` is a mechanism to solve this problem. `Refresh token` can be used to reissue your expired access token.

You can implement it as follows.

```dart
import 'package:twitter_api_v2/twitter_api_v2.dart' as v2;
Future<void> main() async {
final response = await v2.OAuthUtils.refreshAccessToken(
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
refreshToken: 'REFRESH_TOKEN_YOU_GOT',
);
print(response.accessToken);
print(response.refreshToken);
}
```

> **Note**:</br>
> If you are looking for a way to authenticate with **OAuth 2.0 PKCE**, use **[twitter_oauth2_pkce](https://pub.dev/packages/twitter_oauth2_pkce)**.</br>
> The `refresh token` is returned together with the access token by specifying the **`offline.access`** scope to the Twitter authentication server.
### 1.4.5. Null Parameter at Request

In this library, parameters that are not required at request time, i.e., optional parameters, are defined as nullable.
However, developers do not need to be aware of the null parameter when sending requests when using this library.
Expand All @@ -700,7 +728,7 @@ Future<void> main() async {
}
```

### 1.4.5. Expand Object Fields with `expansions`
### 1.4.6. Expand Object Fields with `expansions`

For example, there may be a situation where data contains only an ID, and you want to retrieve the data object associated with that ID as well. In such cases, the `Twitter API v2.0` specification called `expansions` is useful, and this library supports that specification.

Expand Down Expand Up @@ -733,7 +761,7 @@ Future<void> main() async {

You can see more details about `expansions` from [Official Documentation](https://developer.twitter.com/en/docs/twitter-api/expansions).

### 1.4.6. Expand Object Fields with `fields`
### 1.4.7. Expand Object Fields with `fields`

`Twitter API v2.0` supports a very interesting specification, allowing users to control the amount of data contained in the response object for each endpoint depending on the situation. It's called `fields`, and this library supports this specification.

Expand Down Expand Up @@ -774,7 +802,7 @@ Future<void> main() async {
You can see more details about `fields` from [Official Documentation](https://developer.twitter.com/en/docs/twitter-api/fields).

### 1.4.7. JSON Serialization and Deserialization
### 1.4.8. JSON Serialization and Deserialization

All Twitter API responses obtained using **twitter_api_v2** are returned stored in a safe type object. However, there may be cases where the raw JSON returned from the Twitter API is needed when creating applications in combination with other libraries.

Expand Down Expand Up @@ -832,7 +860,7 @@ Future<void> main() async {
}
```

### 1.4.8. OAuth 2.0 Authorization Code Flow with PKCE
### 1.4.9. OAuth 2.0 Authorization Code Flow with PKCE

**Twitter API v2.0** supports authentication methods with [OAuth 2.0 PKCE](https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code), and it allows users of apps using **Twitter API v2.0** to request authorization for the minimum necessary [scope](https://developer.twitter.com/en/docs/authentication/guides/v2-authentication-mapping) of operation.

Expand All @@ -847,7 +875,7 @@ Also, please refer to the next simple sample Flutter application that combines *

- [Example Tweet App](https://github.com/twitter-dart/example-tweet-app-with-twitter-api-v2)

### 1.4.9. Change the Timeout Duration
### 1.4.10. Change the Timeout Duration

The library specifies a default timeout of **10 seconds** for all API communications.

Expand All @@ -866,7 +894,7 @@ Future<void> main() {
}
```

### 1.4.10. Automatic Retry
### 1.4.11. Automatic Retry

Due to the nature of this library's communication with external systems, timeouts may occur due to inevitable communication failures or temporary crashes of the server to which requests are sent.

Expand All @@ -878,7 +906,7 @@ The errors subject to retry are as follows.
- When the network is temporarily lost and `SocketException` is thrown.
- When communication times out temporarily and `TimeoutException` is thrown

#### 1.4.10.1. Exponential BackOff and Jitter
#### 1.4.11.1. Exponential BackOff and Jitter

The easiest way to perform an automatic retry is to stop the process at a certain time and rerun it until it succeeds. However, if there is a network outage on Twitter's servers, sending multiple requests to a specific server at the same time may further overload the server to which the request is sent and further reduce the success rate of retry attempts.

Expand All @@ -905,7 +933,7 @@ In the above implementation, the interval increases exponentially for each retry

> **(2 ^ retryCount) + jitter(Random Number between 0 ~ 3)**
#### 1.4.10.2. Do Something on Retry
#### 1.4.11.2. Do Something on Retry

It would be useful to output logging on retries and a popup notifying the user that a retry has been executed. So **twitter_api_v2** provides callbacks that can perform arbitrary processing when retries are executed.

Expand All @@ -930,7 +958,7 @@ Future<void> main() async {

The [RetryEvent](https://pub.dev/documentation/twitter_api_v2/latest/twitter_api_v2/RetryEvent-class.html) passed to the callback contains information on retries.

### 1.4.11. Meaning of the Returned Boolean
### 1.4.12. Meaning of the Returned Boolean

A boolean value is returned from the endpoint when the communication is primarily POST, DELETE, or PUT.

Expand All @@ -950,7 +978,7 @@ Note that this specification differs from the official [Twitter API v2.0](https:

However, as mentioned earlier in **twitter_api_v2**, for example if you use the [createRetweet](https://pub.dev/documentation/twitter_api_v2/latest/twitter_api_v2/TweetsService/createRetweet.html) method, it will return a **flag indicating whether the process was successful or not**. This principle applies not only to the [createRetweet](https://pub.dev/documentation/twitter_api_v2/latest/twitter_api_v2/TweetsService/createRetweet.html) method, but to all methods that return flags as a result of processing.

### 1.4.12. Thrown Exceptions
### 1.4.13. Thrown Exceptions

**twitter_api_v2** provides a convenient exception object for easy handling of exceptional responses and errors returned from [Twitter API v2.0](https://developer.twitter.com/en/docs/twitter-api/data-dictionary/introduction).

Expand Down Expand Up @@ -995,7 +1023,7 @@ Future<void> main() async {
}
```

### 1.4.13. Upload Media
### 1.4.14. Upload Media

Uploading media on Twitter and sharing it with various people is a very interesting activity. Also, from a business perspective, accompanying tweets with media will attract even more interest from people.

Expand Down Expand Up @@ -1046,7 +1074,7 @@ This upload process works very safely, but note that [TwitterUploadException](ht
> **Note**</br>
> Also note that the v1.1 endpoint is used to achieve this specification in twitter_api_v2. This is because the official Twitter API v2.0 does not yet support media uploads. While I'm trying to keep the implementation as non-disruptive as possible in the future, there may be disruptive changes when media uploads are supported by the official Twitter API v2.0.
### 1.4.14. Check the Progress of Media Upload
### 1.4.15. Check the Progress of Media Upload

Uploading small images to Twitter does not take long, but uploading large videos takes longer to complete. At that time, it would be very useful if you could show users how far along we are in the uploading process.

Expand Down Expand Up @@ -1118,7 +1146,7 @@ And the trigger that calls the `onProgress` callback is as follows. But if the m

Note that media uploads may also fail for reasons such as broken media. In such cases, [TwitterUploadException](https://pub.dev/documentation/twitter_api_core/latest/twitter_api_core/TwitterUploadException-class.html) is always thrown.

### 1.4.15. Generate Filtering Rules Safely and Easily
### 1.4.16. Generate Filtering Rules Safely and Easily

Some endpoints in [Twitter API v2.0](https://developer.twitter.com/en/docs/twitter-api/data-dictionary/introduction) supports a number of operators for advanced searches, not just `keywords` and `hashtags`.

Expand Down
62 changes: 62 additions & 0 deletions lib/src/core/oauth_response.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2022 Kato Shinya. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided the conditions.

// ignore_for_file: invalid_annotation_target

// 📦 Package imports:
import 'package:freezed_annotation/freezed_annotation.dart';

// 🌎 Project imports:
import 'scope.dart';

part 'oauth_response.freezed.dart';
part 'oauth_response.g.dart';

@freezed
class OAuthResponse with _$OAuthResponse {
// ignore: unused_element
const OAuthResponse._();

const factory OAuthResponse({
required String accessToken,
required String refreshToken,
@JsonKey(name: 'scope') @ScopeConverter() required List<Scope> scopes,
@JsonKey(name: 'expires_in')
@DateTimeConverter()
required DateTime expiresAt,
}) = _OAuthResponse;

factory OAuthResponse.fromJson(Map<String, Object?> json) =>
_$OAuthResponseFromJson(json);

/// Returns true if the access token is expired, otherwise false.
bool get isExpired => DateTime.now().isAfter(expiresAt);

/// Returns true if the access token is valid, otherwise false.
bool get isNotExpired => !isExpired;
}

class ScopeConverter implements JsonConverter<List<Scope>, String> {
const ScopeConverter();

@override
List<Scope> fromJson(final String scope) =>
scope.split(' ').map((e) => Scope.valueOf(e)).toList();

@override
String toJson(final List<Scope> scopes) =>
scopes.map((e) => e.value).toList().join(' ');
}

class DateTimeConverter implements JsonConverter<DateTime, int> {
const DateTimeConverter();

@override
DateTime fromJson(final int json) => DateTime.now().add(
Duration(seconds: json),
);

@override
int toJson(final DateTime json) => 7200;
}
Loading

0 comments on commit e53e6ed

Please sign in to comment.