Пример #1
0
        //[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));
        }
Пример #7
0
        /// <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));
        }
Пример #9
0
        /// <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));
        }
Пример #11
0
 /// <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;
 }
Пример #12
0
        /// <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));
        }
Пример #13
0
        /// <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));
        }
Пример #14
0
        /// <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));
        }