-
-
Save alexeyzimarev/62d77bb25d7aa5bb4b9685461f8aabdd to your computer and use it in GitHub Desktop.
using System.Text.Json.Serialization; | |
using RestSharp.Authenticators; | |
namespace RestSharp.Tests.External.Twitter; | |
public interface ITwitterClient { | |
Task<TwitterUser> GetUser(string user); | |
} | |
public class TwitterClient : ITwitterClient, IDisposable { | |
readonly RestClient _client; | |
public TwitterClient(string apiKey, string apiKeySecret) { | |
var options = new RestClientOptions("https://api.twitter.com/2"); | |
_client = new RestClient(options) { | |
Authenticator = new TwitterAuthenticator("https://api.twitter.com", apiKey, apiKeySecret) | |
}; | |
} | |
public async Task<TwitterUser> GetUser(string user) { | |
var response = await _client.GetJsonAsync<TwitterSingleObject<TwitterUser>>( | |
"users/by/username/{user}", | |
new { user } | |
); | |
return response!.Data; | |
} | |
record TwitterSingleObject<T>(T Data); | |
public void Dispose() { | |
_client?.Dispose(); | |
GC.SuppressFinalize(this); | |
} | |
} | |
public class TwitterAuthenticator : AuthenticatorBase { | |
readonly string _baseUrl; | |
readonly string _clientId; | |
readonly string _clientSecret; | |
public TwitterAuthenticator(string baseUrl, string clientId, string clientSecret) : base("") { | |
_baseUrl = baseUrl; | |
_clientId = clientId; | |
_clientSecret = clientSecret; | |
} | |
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken) { | |
var token = string.IsNullOrEmpty(Token) ? await GetToken() : Token; | |
return new HeaderParameter(KnownHeaders.Authorization, token); | |
} | |
async Task<string> GetToken() { | |
var options = new RestClientOptions(_baseUrl); | |
using var client = new RestClient(options) { | |
Authenticator = new HttpBasicAuthenticator(_clientId, _clientSecret), | |
}; | |
var request = new RestRequest("oauth2/token") | |
.AddParameter("grant_type", "client_credentials"); | |
var response = await client.PostAsync<TokenResponse>(request); | |
return $"{response!.TokenType} {response!.AccessToken}"; | |
} | |
record TokenResponse { | |
[JsonPropertyName("token_type")] | |
public string TokenType { get; init; } | |
[JsonPropertyName("access_token")] | |
public string AccessToken { get; init; } | |
} | |
} | |
public record TwitterUser(string Id, string Name, string Username); |
means every client request will get a new token
Adding one line after line 49 solves it, I am not sure why it's such a big issue
Token = token;
I created a updated version that handle expiration date, for anyway interested is over here:
https://gist.github.com/vanderlei-dev/665d7cd7c90aee0bf3e38e83dad5c7d2
Thanks @alexeyzimarev for the base example.
Cool! Thanks @vanderlei-dev
v107 documentation is not correct.
_client = new RestClient(options)
{
Authenticator = new TwitterAuthenticator("https://api.twitter.com", apiKey, apiKeySecret)
};
The above code will NOT compile because Authenticator is getter and can not be set.
I appreciate the report, but it would've been better to open an issue in the RestSharp repository rather than commenting on my old gist.
@keyse just inform during the creation of the RestClientOptions instance:
async Task<TokenResponse> GetToken()
{
//here
var options = new RestClientOptions(_baseUrl){ Authenticator = new HttpBasicAuthenticator(_clientId, _clientSecret) };
//not here
using var client = new RestClient(options) { // Authenticator = new HttpBasicAuthenticator(_clientId, _clientSecret) };
var request = new RestRequest("oauth2/token") .AddParameter("grant_type", "client_credentials");
return await client.PostAsync<TokenResponse>(request);
}
@alexeyzimarev thanks for your example, it was a great help!
@miai-demant feel free to provide a better example. I never claimed that it should be considered as production code. It is, as described, an example.