using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Net; using System.Threading; using System.Threading.Tasks; using Octokit.Internal; namespace Octokit { /// /// A connection for making API requests against URI endpoints. /// Provides type-friendly convenience methods that wrap methods. /// public class ApiConnection : IApiConnection { readonly IApiPagination _pagination; /// /// Initializes a new instance of the class. /// /// A connection for making HTTP requests public ApiConnection(IConnection connection) : this(connection, new ApiPagination()) { } /// /// Initializes a new instance of the class. /// /// A connection for making HTTP requests /// A pagination for paging API responses protected ApiConnection(IConnection connection, IApiPagination pagination) { Ensure.ArgumentNotNull(connection, nameof(connection)); Ensure.ArgumentNotNull(pagination, nameof(pagination)); Connection = connection; _pagination = pagination; } /// /// The underlying connection. /// public IConnection Connection { get; private set; } /// /// Gets the API resource at the specified URI. /// /// Type of the API resource to get. /// URI of the API resource to get /// The API resource. /// Thrown when an API error occurs. public Task Get(Uri uri) { Ensure.ArgumentNotNull(uri, nameof(uri)); return Get(uri, null); } /// /// Gets the API resource at the specified URI. /// /// Type of the API resource to get. /// URI of the API resource to get /// Parameters to add to the API request /// The API resource. /// Thrown when an API error occurs. public async Task Get(Uri uri, IDictionary parameters) { Ensure.ArgumentNotNull(uri, nameof(uri)); var response = await Connection.Get(uri, parameters, null).ConfigureAwait(false); return response.Body; } /// /// Gets the API resource at the specified URI. /// /// Type of the API resource to get. /// URI of the API resource to get /// Parameters to add to the API request /// Accept header to use for the API request /// The API resource. /// Thrown when an API error occurs. public async Task Get(Uri uri, IDictionary parameters, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(accepts, nameof(accepts)); var response = await Connection.Get(uri, parameters, accepts).ConfigureAwait(false); return response.Body; } /// /// Gets the HTML content of the API resource at the specified URI. /// /// URI of the API resource to get /// Parameters to add to the API request /// The API resource's HTML content. /// Thrown when an API error occurs. public async Task GetHtml(Uri uri, IDictionary parameters) { Ensure.ArgumentNotNull(uri, nameof(uri)); var response = await Connection.GetHtml(uri, parameters).ConfigureAwait(false); return response.Body; } /// /// Gets the raw content of the API resource at the specified URI. /// /// URI of the API resource to get /// Parameters to add to the API request /// The API resource's raw content or null if the points to a directory. /// Thrown when an API error occurs. public async Task GetRaw(Uri uri, IDictionary parameters) { Ensure.ArgumentNotNull(uri, nameof(uri)); var response = await Connection.GetRaw(uri, parameters).ConfigureAwait(false); return response.Body; } /// /// Gets all API resources in the list at the specified URI. /// /// Type of the API resource in the list. /// URI of the API resource to get /// of the API resources in the list. /// Thrown when an API error occurs. public Task> GetAll(Uri uri) { return GetAll(uri, ApiOptions.None); } /// /// Gets all API resources in the list at the specified URI. /// /// Type of the API resource in the list. /// URI of the API resource to get /// Options for changing the API response /// of the API resources in the list. /// Thrown when an API error occurs. public Task> GetAll(Uri uri, ApiOptions options) { return GetAll(uri, null, null, options); } /// /// Gets all API resources in the list at the specified URI. /// /// Type of the API resource in the list. /// URI of the API resource to get /// Parameters to add to the API request /// of the API resources in the list. /// Thrown when an API error occurs. public Task> GetAll(Uri uri, IDictionary parameters) { return GetAll(uri, parameters, null, ApiOptions.None); } /// /// Gets all API resources in the list at the specified URI. /// /// Type of the API resource in the list. /// URI of the API resource to get /// Accept header to use for the API request /// of the API resources in the list. /// Thrown when an API error occurs. public Task> GetAll(Uri uri, string accepts) { return GetAll(uri, null, accepts, ApiOptions.None); } /// /// Gets all API resources in the list at the specified URI. /// /// Type of the API resource in the list. /// URI of the API resource to get /// Parameters to add to the API request /// Options for changing the API response /// of the API resources in the list. /// Thrown when an API error occurs. public Task> GetAll(Uri uri, IDictionary parameters, ApiOptions options) { return GetAll(uri, parameters, null, options); } /// /// Gets all API resources in the list at the specified URI. /// /// Type of the API resource in the list. /// URI of the API resource to get /// Parameters to add to the API request /// Accept header to use for the API request /// of the API resources in the list. /// Thrown when an API error occurs. public Task> GetAll(Uri uri, IDictionary parameters, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); return _pagination.GetAllPages(async () => await GetPage(uri, parameters, accepts).ConfigureAwait(false), uri); } public Task> GetAll(Uri uri, IDictionary parameters, string accepts, ApiOptions options) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(options, nameof(options)); parameters = Pagination.Setup(parameters, options); return _pagination.GetAllPages(async () => await GetPage(uri, parameters, accepts, options).ConfigureAwait(false), uri); } /// /// Creates a new API resource in the list at the specified URI. /// /// URI endpoint to send request to /// An optional token to monitor for cancellation requests /// Representing the received HTTP response /// Thrown when an API error occurs. public Task Post(Uri uri, CancellationToken cancellationToken = default) { Ensure.ArgumentNotNull(uri, nameof(uri)); return Connection.Post(uri, cancellationToken); } /// /// Creates a new API resource in the list at the specified URI. /// /// The API resource's type. /// URI of the API resource to get /// An optional token to monitor for cancellation requests /// The created API resource. /// Thrown when an API error occurs. public async Task Post(Uri uri, CancellationToken cancellationToken = default) { Ensure.ArgumentNotNull(uri, nameof(uri)); var response = await Connection.Post(uri, cancellationToken).ConfigureAwait(false); return response.Body; } /// /// Creates a new API resource in the list at the specified URI. /// /// The API resource's type. /// URI of the API resource to get /// Object that describes the new API resource; this will be serialized and used as the request's body /// An optional token to monitor for cancellation requests /// The created API resource. /// Thrown when an API error occurs. public Task Post(Uri uri, object data, CancellationToken cancellationToken = default) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); return Post(uri, data, null, null, cancellationToken); } /// /// Creates a new API resource in the list at the specified URI. /// /// The API resource's type. /// URI of the API resource to get /// Object that describes the new API resource; this will be serialized and used as the request's body /// Accept header to use for the API request /// An optional token to monitor for cancellation requests /// The created API resource. /// Thrown when an API error occurs. public Task Post(Uri uri, object data, string accepts, CancellationToken cancellationToken = default) { return Post(uri, data, accepts, null, cancellationToken); } /// /// Creates a new API resource in the list at the specified URI. /// /// The API resource's type. /// URI of the API resource to get /// Object that describes the new API resource; this will be serialized and used as the request's body /// Accept header to use for the API request /// Content type of the API request /// An optional token to monitor for cancellation requests /// The created API resource. /// Thrown when an API error occurs. public async Task Post(Uri uri, object data, string accepts, string contentType, CancellationToken cancellationToken = default) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); var response = await Connection.Post(uri, data, accepts, contentType, cancellationToken: cancellationToken).ConfigureAwait(false); return response.Body; } /// /// Creates a new API resource in the list at the specified URI. /// /// The API resource's type. /// URI of the API resource to get /// Object that describes the new API resource; this will be serialized and used as the request's body /// Accept header to use for the API request /// Content type of the API request /// Two Factor Authentication Code /// An optional token to monitor for cancellation requests /// The created API resource. /// Thrown when an API error occurs. public async Task Post(Uri uri, object data, string accepts, string contentType, string twoFactorAuthenticationCode, CancellationToken cancellationToken = default) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); Ensure.ArgumentNotNull(twoFactorAuthenticationCode, nameof(twoFactorAuthenticationCode)); var response = await Connection.Post(uri, data, accepts, contentType, twoFactorAuthenticationCode, cancellationToken).ConfigureAwait(false); return response.Body; } public async Task Post(Uri uri, object data, string accepts, string contentType, TimeSpan timeout, CancellationToken cancellationToken = default) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); var response = await Connection.Post(uri, data, accepts, contentType, timeout, cancellationToken).ConfigureAwait(false); return response.Body; } /// /// Creates or replaces the API resource at the specified URI /// /// URI of the API resource to put /// A for the request's execution. public Task Put(Uri uri) { Ensure.ArgumentNotNull(uri, nameof(uri)); return Connection.Put(uri); } /// /// Creates or replaces the API resource at the specified URI. /// /// The API resource's type. /// URI of the API resource to create or replace /// Object that describes the API resource; this will be serialized and used as the request's body /// The created API resource. /// Thrown when an API error occurs. public async Task Put(Uri uri, object data) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); var response = await Connection.Put(uri, data).ConfigureAwait(false); return response.Body; } /// /// Creates or replaces the API resource at the specified URI. /// /// The API resource's type. /// URI of the API resource to create or replace /// Object that describes the API resource; this will be serialized and used as the request's body /// The two-factor authentication code in response to the current user's previous challenge /// The created API resource. /// Thrown when an API error occurs. public async Task Put(Uri uri, object data, string twoFactorAuthenticationCode) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); Ensure.ArgumentNotNullOrEmptyString(twoFactorAuthenticationCode, nameof(twoFactorAuthenticationCode)); var response = await Connection.Put(uri, data, twoFactorAuthenticationCode).ConfigureAwait(false); return response.Body; } /// /// Creates or replaces the API resource at the specified URI. /// /// The API resource's type. /// URI of the API resource to create or replace /// Object that describes the API resource; this will be serialized and used as the request's body /// The two-factor authentication code in response to the current user's previous challenge /// Accept header to use for the API request /// The created API resource. /// Thrown when an API error occurs. public async Task Put(Uri uri, object data, string twoFactorAuthenticationCode, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); var response = await Connection.Put(uri, data, twoFactorAuthenticationCode, accepts).ConfigureAwait(false); return response.Body; } /// /// Updates the API resource at the specified URI. /// /// URI of the API resource to patch /// A for the request's execution. public Task Patch(Uri uri) { Ensure.ArgumentNotNull(uri, nameof(uri)); return Connection.Patch(uri); } /// /// Updates the API resource at the specified URI. /// /// URI of the API resource to patch /// Accept header to use for the API request /// A for the request's execution. public Task Patch(Uri uri, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(accepts, nameof(accepts)); return Connection.Patch(uri, accepts); } /// /// Updates the API resource at the specified URI. /// /// The API resource's type. /// URI of the API resource to update /// Object that describes the API resource; this will be serialized and used as the request's body /// The updated API resource. /// Thrown when an API error occurs. public async Task Patch(Uri uri, object data) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); var response = await Connection.Patch(uri, data).ConfigureAwait(false); return response.Body; } /// /// Updates the API resource at the specified URI. /// /// The API resource's type. /// URI of the API resource to update /// Object that describes the API resource; this will be serialized and used as the request's body /// Accept header to use for the API request /// The updated API resource. /// Thrown when an API error occurs. public async Task Patch(Uri uri, object data, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); Ensure.ArgumentNotNull(accepts, nameof(accepts)); var response = await Connection.Patch(uri, data, accepts).ConfigureAwait(false); return response.Body; } /// /// Deletes the API object at the specified URI. /// /// URI of the API resource to delete /// A for the request's execution. public Task Delete(Uri uri) { Ensure.ArgumentNotNull(uri, nameof(uri)); return Connection.Delete(uri); } /// /// Deletes the API object at the specified URI. /// /// URI of the API resource to delete /// Two Factor Code /// A for the request's execution. public Task Delete(Uri uri, string twoFactorAuthenticationCode) { Ensure.ArgumentNotNull(uri, nameof(uri)); return Connection.Delete(uri, twoFactorAuthenticationCode); } /// /// Deletes the API object at the specified URI. /// /// URI of the API resource to delete /// Object that describes the API resource; this will be serialized and used as the request's body /// A for the request's execution. public Task Delete(Uri uri, object data) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); return Connection.Delete(uri, data); } /// /// Performs an asynchronous HTTP DELETE request that expects an empty response. /// /// URI endpoint to send request to /// The object to serialize as the body of the request /// Specifies accept response media type /// The returned public Task Delete(Uri uri, object data, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); Ensure.ArgumentNotNull(accepts, nameof(accepts)); return Connection.Delete(uri, data, accepts); } /// /// Performs an asynchronous HTTP DELETE request. /// /// The API resource's type. /// URI endpoint to send request to /// The object to serialize as the body of the request public async Task Delete(Uri uri, object data) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); var response = await Connection.Delete(uri, data).ConfigureAwait(false); return response.Body; } /// /// Performs an asynchronous HTTP DELETE request. /// Attempts to map the response body to an object of type /// /// The API resource's type. /// URI endpoint to send request to /// Specifies accept response media type /// The returned public async Task Delete(Uri uri, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(accepts, nameof(accepts)); var response = await Connection.Delete(uri, null, accepts).ConfigureAwait(false); return response.Body; } /// /// Performs an asynchronous HTTP DELETE request. /// Attempts to map the response body to an object of type /// /// The type to map the response to /// URI endpoint to send request to /// The object to serialize as the body of the request /// Specifies accept response media type public async Task Delete(Uri uri, object data, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); Ensure.ArgumentNotNull(data, nameof(data)); Ensure.ArgumentNotNull(accepts, nameof(accepts)); var response = await Connection.Delete(uri, data, accepts).ConfigureAwait(false); return response.Body; } /// /// Executes a GET to the API object at the specified URI. This operation is appropriate for API calls which /// queue long running calculations and return a collection of a resource. /// It expects the API to respond with an initial 202 Accepted, and queries again until a 200 OK is received. /// It returns an empty collection if it receives a 204 No Content response. /// /// The API resource's type. /// URI of the API resource to update /// A token used to cancel this potentially long running request /// The updated API resource. /// Thrown when an API error occurs. public async Task> GetQueuedOperation(Uri uri, CancellationToken cancellationToken) { while (true) { Ensure.ArgumentNotNull(uri, nameof(uri)); var response = await Connection.GetResponse>(uri, cancellationToken).ConfigureAwait(false); switch (response.HttpResponse.StatusCode) { case HttpStatusCode.Accepted: continue; case HttpStatusCode.NoContent: return new ReadOnlyCollection(new T[] { }); case HttpStatusCode.OK: return response.Body; } throw new ApiException("Queued Operations expect status codes of Accepted, No Content, or OK.", response.HttpResponse.StatusCode); } } async Task> GetPage( Uri uri, IDictionary parameters, string accepts) { Ensure.ArgumentNotNull(uri, nameof(uri)); var response = await Connection.Get>(uri, parameters, accepts).ConfigureAwait(false); return new ReadOnlyPagedCollection( response, nextPageUri => Connection.Get>(nextPageUri, parameters, accepts)); } async Task> GetPage( Uri uri, IDictionary parameters, string accepts, ApiOptions options) { Ensure.ArgumentNotNull(uri, nameof(uri)); var connection = Connection; var response = await connection.Get>(uri, parameters, accepts).ConfigureAwait(false); return new ReadOnlyPagedCollection( response, nextPageUri => { var shouldContinue = Pagination.ShouldContinue( nextPageUri, options); return shouldContinue ? connection.Get>(nextPageUri, parameters, accepts) : null; }); } } }