//[Fact] public async Task IamportRequest_has_token_header() { // arrange var options = GetMockOptions(); var mock = new Mock <HttpClient>(); mock.Setup(client => client.SendAsync( It.Is <HttpRequestMessage>( message => message.Headers.GetValues(DefaultTokenHeaderName).Any()), It.IsAny <CancellationToken>())) .ReturnsAsync(new HttpResponseMessage { Content = new JsonContent(JsonConvert.SerializeObject(FailedTokenResponse)) }); var sut = new IamportHttpClient(options, mock.Object); var request = new IamportRequest <object> { ApiPathAndQueryString = "/self", RequireAuthorization = true }; // act var result = await sut.RequestAsync <object, object>(request); // assert mock.Verify(client => client.SendAsync( It.Is <HttpRequestMessage>( message => message .Headers .GetValues(DefaultTokenHeaderName) .Any()), It.IsAny <CancellationToken>()), Times.Once); }
private async Task <TResult> SendRequestAsync <TRequest, TResult>(IamportRequest <TRequest> request) { var response = await client.RequestAsync <TRequest, TResult>(request); if (response.Code != Constants.ResponseSuccessCode) { throw new IamportResponseException(response.Code, response.Message); } return(response.Content); }
/// <summary> /// 주어진 아임포트 요청 정보에 해당하는 HttpRequestMessage를 반환합니다. /// </summary> /// <typeparam name="TRequest">요청 정보의 타입</typeparam> /// <param name="request">요청 정보</param> /// <returns>HttpRequestMessage</returns> protected HttpRequestMessage GetHttpRequest <TRequest>(IamportRequest <TRequest> request) { var url = ApiPathUtility.Build(options.BaseUrl, request.ApiPathAndQueryString); var httpRequest = new HttpRequestMessage(request.Method, url); if (request.Method != HttpMethod.Get) { httpRequest.Content = new JsonContent(request.Content); } return(httpRequest); }
/// <summary> /// 아임포트 고유 ID에 해당하는 결제 결과를 조회합니다. /// 존재하지 않을 경우 null을 반환합니다. /// </summary> /// <param name="iamportId">아임포트 고유 ID</param> /// <seealso>https://api.iamport.kr/#!/payments/getPaymentByImpUid</seealso> /// <returns>결제 결과</returns> public async Task <Payment> GetByIamportIdAsync(string iamportId) { if (string.IsNullOrEmpty(iamportId)) { throw new ArgumentNullException(nameof(iamportId)); } var request = new IamportRequest { ApiPathAndQueryString = GetPathAndQuerystring(iamportId), Method = HttpMethod.Get, }; return(await SendRequestAsync <object, Payment>(request)); }
/// <summary> /// 주어진 거래 ID에 해당하는 결제 준비 정보를 반환합니다. /// 존재하지 않을 경우 null을 반환합니다. /// </summary> /// <param name="transactionId">거래 ID</param> /// <seealso>https://api.iamport.kr/#!/payments.validation/getPaymentPrepareByMerchantUid</seealso> /// <returns>결제 준비 정보</returns> public async Task <PaymentPreparation> GetPreparationAsync(string transactionId) { if (string.IsNullOrEmpty(transactionId)) { throw new ArgumentNullException(nameof(transactionId)); } var request = new IamportRequest { ApiPathAndQueryString = GetPathAndQuerystring($"prepare/{transactionId}"), Method = HttpMethod.Get, }; return(await SendRequestAsync <object, PaymentPreparation>(request)); }
/// <summary> /// 거래 ID에 해당하는 결제 결과를 조회합니다. /// 존재하지 않을 경우 null을 반환합니다. /// </summary> /// <param name="transactionId">거래 ID</param> /// <seealso>https://api.iamport.kr/#!/payments/getPaymentByMerchantUid</seealso> /// <returns>결제 결과</returns> public async Task <Payment> GetByTransactionIdAsync(string transactionId) { if (string.IsNullOrEmpty(transactionId)) { throw new ArgumentNullException(nameof(transactionId)); } var request = new IamportRequest { ApiPathAndQueryString = GetPathAndQuerystring($"find/{WebUtility.UrlEncode(transactionId)}"), Method = HttpMethod.Get, }; return(await SendRequestAsync <object, Payment>(request)); }
/// <summary> /// [DELETE] /subscribe/customers/{customer_uid} /// iamport: 구매자의 빌링키 정보 삭제(DB에서 빌링키를 삭제[delete] 합니다) /// </summary> /// <param name="customerId">구매자 ID</param> /// <returns>구매자 정보</returns> public async Task <Customer> DeleteCustomerAsync(string customerId) { if (string.IsNullOrEmpty(customerId)) { throw new ArgumentNullException(nameof(customerId)); } var request = new IamportRequest { ApiPathAndQueryString = GetCustomersPath(customerId), Method = HttpMethod.Delete }; return(await SendRequestAsync <Customer>(request)); }
/// <summary> /// 주어진 입력에 해당하는 결제를 취소하고 결제 결과를 반환합니다. /// 해당하는 결제 결과가 없으면 null을 반환합니다. /// </summary> /// <param name="cancellation">취소 정보</param> /// <seealso>https://api.iamport.kr/#!/payments/cancelPayment</seealso> /// <returns>결제 결과</returns> public async Task <Payment> CancelAsync(PaymentCancellation cancellation) { if (cancellation == null) { throw new ArgumentNullException(nameof(cancellation)); } ValidateObject(cancellation); var request = new IamportRequest <PaymentCancellation> { ApiPathAndQueryString = GetPathAndQuerystring("cancel"), Content = cancellation, Method = HttpMethod.Post }; return(await SendRequestAsync <PaymentCancellation, Payment>(request)); }
/// <summary> /// [POST] /subscribe/payments/again /// iamport: 저장된 빌링키로 재결제를 하는 경우 사용됩니다. /subscribe/payments/onetime 또는 /subscribe/customers/{customer_uid} 로 등록된 빌링키가 있을 때 매칭되는 customer_uid로 재결제를 진행할 수 있습니다. /// </summary> /// <param name="request">저장된 구매자 정보로 결제를 요청하는 정보</param> /// <returns>결제 결과</returns> public async Task <Payment> DoDirectPaymentAsync(CustomerDirectPaymentRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } ValidateObject(request); var iamportRequest = new IamportRequest <CustomerDirectPaymentRequest> { ApiPathAndQueryString = GetPaymentsPathAndQuerystring("again"), Content = request, Method = HttpMethod.Post }; return(await SendRequestAsync <CustomerDirectPaymentRequest, Payment>(iamportRequest)); }
/// <summary> /// 주어진 정보로 결제를 준비합니다. /// 준비된 결제는 동일한 거래 ID에 대해 단 한번만 결제를 진행할 수 있으며, /// 결제 진행중 등록된 금액과 다를 경우 결제에 실패합니다. /// </summary> /// <param name="preparation">결제 준비 정보</param> /// <seealso>https://api.iamport.kr/#!/payments.validation/preparePayment</seealso> /// <returns>결제 준비 정보</returns> public async Task <PaymentPreparation> PrepareAsync(PaymentPreparation preparation) { if (preparation == null) { throw new ArgumentNullException(nameof(preparation)); } ValidateObject(preparation); var request = new IamportRequest <PaymentPreparation> { ApiPathAndQueryString = GetPathAndQuerystring($"prepare"), Method = HttpMethod.Post, Content = preparation }; return(await SendRequestAsync <PaymentPreparation, PaymentPreparation>(request)); }
/// <summary> /// 주어진 아임포트 토큰 요청을 인증하고 결과 토큰을 반환합니다. /// 인증에 실패하거나 입력 정보에 문제가 있을 경우 예외를 발생시킵니다. /// 이 API 호출은 내부 HttpClient의 Authorization 헤더를 설정하지 않습니다. /// 단지 요청한 토큰 정보에 대한 응답을 반환할 뿐입니다. /// </summary> /// <param name="request">아임포트 토큰 요청</param> /// <seealso>https://api.iamport.kr/#!/authenticate/getToken</seealso> /// <returns>인증된 아임포트 토큰</returns> public virtual async Task<IamportToken> GetTokenAsync(IamportTokenRequest request) { var iamportRequest = new IamportRequest<IamportTokenRequest> { RequireAuthorization = false, ApiPathAndQueryString = $"{BasePath}/{UsersGetTokenPath}", Content = request, Method = HttpMethod.Post, }; var response = await client.RequestAsync<IamportTokenRequest, IamportToken>(iamportRequest); if (response.Code != 0) { throw new IamportResponseException(response.Code, response.Message); } return response.Content; }
/// <summary> /// [POST] /subscribe/customers/{customer_uid} /// iamport: 구매자에 대해 빌링키 발급 및 저장 /// </summary> /// <param name="registration">구매자 등록 정보</param> /// <returns>구매자 정보</returns> public async Task <Customer> RegisterCustomerAsync(CustomerRegistration registration) { if (registration == null) { throw new ArgumentNullException(nameof(registration)); } ValidateObject(registration); var request = new IamportRequest <CustomerRegistration> { ApiPathAndQueryString = GetCustomersPath(registration.Id), Content = registration, Method = HttpMethod.Post }; return(await SendRequestAsync <CustomerRegistration, Customer>(request)); }
/// <summary> /// [POST] /subscribe/payments/unschedule /// iamport: 비인증 결제요청예약 취소 /// </summary> /// <param name="request">예약 취소 정보</param> /// <returns>취소된 스케줄 목록</returns> public async Task <ScheduledPayment[]> UnschedulePaymentsAsync(UnschedulePaymentsRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } ValidateObject(request); var iamportRequest = new IamportRequest <UnschedulePaymentsRequest> { ApiPathAndQueryString = GetPaymentsPathAndQuerystring("unschedule"), Content = request, Method = HttpMethod.Post }; return(await SendRequestAsync <UnschedulePaymentsRequest, ScheduledPayment[]>(iamportRequest)); }
/// <summary> /// 주어진 아임포트 토큰 요청을 인증하고 결과 토큰을 반환합니다. /// 인증에 실패하거나 입력 정보에 문제가 있을 경우 예외를 발생시킵니다. /// 이 API 호출은 내부 HttpClient의 Authorization 헤더를 설정하지 않습니다. /// 단지 요청한 토큰 정보에 대한 응답을 반환할 뿐입니다. /// </summary> /// <param name="request">아임포트 토큰 요청</param> /// <seealso>https://api.iamport.kr/#!/authenticate/getToken</seealso> /// <returns>인증된 아임포트 토큰</returns> public virtual async Task <IamportToken> GetTokenAsync(IamportTokenRequest request) { var iamportRequest = new IamportRequest <IamportTokenRequest> { RequireAuthorization = false, ApiPathAndQueryString = $"{BasePath}/{UsersGetTokenPath}", Content = request, Method = HttpMethod.Post, }; var response = await client.RequestAsync <IamportTokenRequest, IamportToken>(iamportRequest); if (response.Code != 0) { throw new IamportResponseException(response.Code, response.Message); } return(response.Content); }
public async Task RequestIamportRequest_calls_Authorize_after_expired() { // arrange var options = GetMockOptions(); var uri = ApiPathUtility.Build(options.BaseUrl, "/users/getToken"); var mock = new Mock <HttpClient>(); mock.Setup(client => client.SendAsync( It.Is <HttpRequestMessage>( message => message.RequestUri.Equals(uri)), It.IsAny <CancellationToken>())) .ReturnsAsync(new HttpResponseMessage { Content = new JsonContent(JsonConvert.SerializeObject(FastExpiredTokenResponse)) }); var somethingUri = ApiPathUtility.Build(options.BaseUrl, "/something"); mock.Setup(client => client.SendAsync( It.Is <HttpRequestMessage>( message => message.RequestUri.Equals(somethingUri)), It.IsAny <CancellationToken>())) .ReturnsAsync(new HttpResponseMessage { Content = new JsonContent(JsonConvert.SerializeObject(EmptyObjectResponse)) }); var sut = new IamportHttpClient(options, mock.Object); var request = new IamportRequest <object> { ApiPathAndQueryString = "/something", RequireAuthorization = true }; // act; call twice await sut.RequestAsync <object, object>(request); await Task.Delay(15); await sut.RequestAsync <object, object>(request); // assert mock.Verify(client => client.SendAsync( It.Is <HttpRequestMessage>( message => message.RequestUri.Equals(uri)), It.IsAny <CancellationToken>()), Times.Exactly(2)); }
/// <summary> /// 주어진 조회 조건에 해당하는 결제 결과를 조회합니다. /// </summary> /// <param name="query">결제 조회 조건</param> /// <seealso>https://api.iamport.kr/#!/payments/getPaymentsByStatus</seealso> /// <returns>결제 결과의 목록</returns> public async Task <PagedResult <Payment> > GetAsync(PaymentPageQuery query) { if (query == null) { throw new ArgumentNullException(nameof(query)); } var pathAndQuerystring = GetPathAndQuerystring($"status/{query.State.GetMemberValue()}"); if (query.Page > 0) { pathAndQuerystring += $"?page={query.Page}"; } var request = new IamportRequest { ApiPathAndQueryString = pathAndQuerystring, Method = HttpMethod.Get, }; return(await SendRequestAsync <object, PagedResult <Payment> >(request)); }
public async Task Throws_HttpRequestException_for_http_exception() { // arrange var options = GetMockOptions(); var mock = new Mock <HttpClient>(); mock.Setup(client => client.SendAsync( It.IsAny <HttpRequestMessage>(), It.IsAny <CancellationToken>())) .ThrowsAsync(new HttpRequestException("exception")); var sut = new IamportHttpClient(options, mock.Object); var request = new IamportRequest <object> { ApiPathAndQueryString = "/error", RequireAuthorization = false }; // act/assert await Assert.ThrowsAsync <HttpRequestException>( () => sut.RequestAsync <object, object>(request)); }
/// <summary> /// 주어진 정보로 아임포트 서버에 요청을 전송하고 결과를 반환합니다. /// 만약 요청 정보에 RequireAuthorization이 true일 경우 /// 자동으로 Authorize 메서드를 호출합니다. /// </summary> /// <typeparam name="TRequest">요청할 콘텐트의 타입</typeparam> /// <typeparam name="TResult">응답받을 콘텐트의 타입</typeparam> /// <param name="request">요청 정보</param> /// <returns>응답 정보</returns> public async Task <IamportResponse <TResult> > RequestAsync <TRequest, TResult>(IamportRequest <TRequest> request) { ThrowsIfDisposed(); if (request == null) { throw new ArgumentNullException(nameof(request)); } if (request.RequireAuthorization) { await EnsureAuthorizedAsync(); } var httpRequest = GetHttpRequest(request); return(await RequestAsync <TResult>(httpRequest)); }