결제 연동을 할 때 SDK로 하면 편하지만, 가끔 사용하는 모듈들과 충돌을 일으킬 때까 있습니다. 이럴 때를 대비한 REST API로 구현하는 것을 눈여겨 봐두면 좋을 것 같습니다.

저는 서버에서 결제 검증만 할 것 이므로, 토큰을 얻는 것과 클라이언트에서 결제 이후 넘어온 주문 번호를 확인해 결제 정보를 읽어오는 것만 할 것 입니다.

 

1. 결제 연동을 하는 공식 문서.

-> https://developer.paypal.com/docs/api/orders/v2/

이 페이지 하나에 모든 설명이 다들어 있으며,  cURL을 이용해 사용할 수 있도록 되어 있습니다. 맥 같은 경우 cURL이 설치되어 있으므로, 쉽게 사용하며, 윈도우에서는 직접 설치해야할 지도 모르겠습니다.

 

2. nodejs 리퀘스트 설치.

-> npm i request

node js가 설치되어 있다면 위 명령으로 리퀘스트가 설치 됩니다.

 

3. cURL 명령을 request로 바꿔주는 페이지.

-> https://curl.trillworks.com/#node

curl 명령을 node js에서 request로 바꿔 주려면 조금 귀찮은 면이 있는데 이 사이트를 이용하면, 쉽게 변경할 수 있습니다.

 

4. AccessToken 얻기

-> https://developer.paypal.com/docs/api/get-an-access-token-curl/

위 페이지에 cURL 명령에서 client_id와 시크릿을 바꿔 넣으면 access 토큰을 얻을 수 있습니다. 명령은 아래와 같습니다. \는 그냥 한줄로 계속 써야한다는 의미 입니다.

curl -v https://api.sandbox.paypal.com/v1/oauth2/token \
   -H "Accept: application/json" \
   -H "Accept-Language: en_US" \
   -u "client_id:secret" \
   -d "grant_type=client_credentials"

 

5. 결제 정보 얻기

-> https://developer.paypal.com/docs/api/orders/v2/

위 페이지에서 show order details 항목을 참고 하면 구매했던 상품의 정보를 확인할 수 있습니다. cURL 명령은 아래와 같습니다.

curl -v -X GET https://api.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T \
-H "Content-Type: application/json" \
-H "Authorization: Bearer Access-Token"

 

6. 예제 소스.

아래 소스를 그대로 가져가셔서 약간 수정해 페이팔 검증으로 사용하셔도 됩니다. 그래도 cURL로 잘되는 지 먼저 확인하시는 편이 좋습니다. (c_Util은 제가 응답을 json으로 보내기 위해, 만든 클래스 입니다.)

// 기본 모듈들 입니다.

// npm 으로 다운로드 받은 파일 입니다.
const request = require('request');

// ags에서 설정한 파일들 입니다.
const c_Util = require( './c_Util' );



//  --- --- --- ---     전역에 공개되는 값들 입니다.

// 전역 변수를 설정합니다.
let clientID = "";
let secret = "";



// 클래스를 초기화 하는 메소드 입니다.
module.exports.init = function(
    _isSandbox, _sandbox_client_id, _sandbox_secret, _live_client_id, _live_secret
){



    // 샌드 박스인 경우, 클라이언트와 시크릿을 설정합니다.
    if( _isSandbox )
    {

        console.log( "페이팔은 샌드박스로 동작합니다." );
        clientID = _sandbox_client_id;
        secret = _sandbox_secret;

    }

    // 라이브 인경우, 클라이언트와 시크릿을 설정합니다.
    else
    {

        console.log( "페이팔은 라이브로 동작합니다." );
        clientID = _live_client_id;
        secret = _live_secret;

    }


    console.log( "페이팔 클라이언트키:시크릿" + clientID + ":"+ secret );



}



// 클래스를 생성하는 메소드 입니다.
module.exports.create = function()
{



    //  --- --- --- ---     초기화 및 반환객체를 만들어 줍니다.
    let rINSTANCE = {};



    //  --- --- --- ---     에세스 토큰 획득 관련 메소드들 입니다.

    // 에세스 토큰을 가지고오는 메소드 입니다.
    rINSTANCE.getAccessToken = function()
    {

        return new Promise(function( resolve, reject ){

            let headers = {
                'Accept': 'application/json',
                'Accept-Language': 'en_US'
            };
            
            let dataString = 'grant_type=client_credentials';
            
            let options = {
                url: 'https://api.sandbox.paypal.com/v1/oauth2/token',
                method: 'POST',
                headers: headers,
                body: dataString,
                auth: {
                    'user': clientID,
                    'pass': secret
                }
            };

            
            function callback(error, response, body) {


                // 에러가 있다면 오류를 반환하고 종료합니다.
                if( error )
                {

                    let unknownError = c_Util.res_Message( {}, "에세스 토큰을 가지고 오던 중 알 수 없는 오류를 만났습니다.", 5 );
                    unknownError.detailError = error;
                    resolve( unknownError );

                }


                // 에러가 없다면 정상적인 결과를 반환합니다.
                else
                {

                    //  받은 값은 문자열 이므로, 객체로 바꿔 줍니다.
                    let resObj = JSON.parse( body );
                    resolve( resObj.access_token );
                    
                }


            }
            
            request(options, callback);
            

        });

    }



    //  --- --- --- ---      체크 아웃 관련 메소드들 입니다.

    // 상품 결제 정보가 유효한지 확인하는 메소드 입니다.
    rINSTANCE.getProduct = function( _accessToken, _orderId )
    {

        return new Promise( function( resolve, reject ){


            let headers = {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + _accessToken
            };

            let options = {
                url: 'https://api.sandbox.paypal.com/v2/checkout/orders/' + _orderId,
                headers: headers
            };

            function callback(error, response, body) {

                // 오류가 난 경우 오류를 처리하도록 합니다.
                if( error )
                {

                    let unknownError = c_Util.res_Message( {}, "결제 정보를 확인하던 중 오류를 만났습니다.", 5 );
                    unknownError.detailError = error;
                    resolve( unknownError );
                    return;
                    
                }

                else
                {

                    let successResult = JSON.parse( body );
                    resolve( successResult );
                    return;

                }

            }

            request(options, callback);

        } );

    }







    //  --- --- --- ---     마무리 및 인스턴스 객체를 반환합니다.

    return rINSTANCE;




}




















































// 문서의 끝 입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Posted by 창업닉군
,

페이팔은 결제 연동이 매우 간단한 편이라, 따로 소스는 두지 않았고, 주의 사항만 메모를 해 두었습니다.

 

1. 개발 사이트

-> https://developer.paypal.com

페이팔은 테스트를 위한 SANDBOX 서버, 실제 거래를 위한 LIVE 서버를 운영하고 있습니다. SANDBOX 와 LIVE 서버는 같은 앱이라도 각각 다른 클라이언트 ID, 시크릿을 설정해 주어야 합니다.

 

2. 체크 아웃 예제 페이지.

-> https://developer.paypal.com/docs/checkout/integrate/#

클라이언트 아이디만 넣어 주고, 그냥 소스를 붙여 넣기만 해도 잘 동작합니다. 영수증 검증에 사용되는 값은, 결제 후 받는 data의 orderID, 혹은 details의 id 값을 넣으면 됩니다. (둘이 같은 값 입니다.). 이 페이지만 따라 하면 모든 연동이 끝이 납니다.

 

3. 클라이언트 SDK 설정.

클라이언트 SDK 설정에는 클라이언트 아이디만 넣어주면 기본적으로 설저이 끝이 나지만, 추가 옵션으로 통화 등을 설정할 수 있습니다.

 

4. 서버사이드 설정.

-> https://developer.paypal.com/docs/checkout/reference/server-integration/setup-sdk/

서버 사이드 설정의 SDK 설치 방법은 의외로 눈에 잘 띄지 않는데, 이 페이지에 있습니다.

 

5. 서버에서 결제 셋팅.

->  https://developer.paypal.com/docs/checkout/reference/server-integration/set-up-transaction/

서버에서 결제 처리를 할 이유는 잘 없지만, 페이팔에서 가능합니다. 일단 링크를 걸어 둡니다.

 

6. 결제.

-> https://developer.paypal.com/docs/checkout/reference/server-integration/capture-transaction/#on-the-server

capture는 실제 결제 처리를 하는 부분입니다. 만약 클라이언트에서 넘어온, 결제를 이 루틴으로 검증하려고 하면 오류를 만납니다. 결제는 아래 결제 확인 부분에서 처리하면됩니다.

 

7. 결제 확인.

-> https://developer.paypal.com/docs/checkout/reference/server-integration/get-transaction/

클라이언트에서 결제 하면 서버에서 주로 결제를 확인하는데 이 부분에서 하게 됩니다. 많이 쓰게 되니 소스 코드를 봐 두세요. 결제 확인 이후 res.json 등의 헤더 변경을 하는 방법으로 소스를 보내면 오류를 만납니다. res.end 메소드로 응답을 보내 주세요.

 

8. 예제.

-> https://github.com/paypal/Checkout-Nodejs-SDK/

문서에 있는 코드들을 보면, 쉽게 이해가 가지 않습니다. 생략된 것들이 많이서 인데, 일단 예제를 보면 쉽게 이해가 갑니다. 위 문서를 잘 읽어 보셨다면, 보자 마자 이해가 될 정도 입니다.

예제는 아래와 같이 들어 가면됩니다.

1. https://developer.paypal.com/docs/checkout/reference/server-integration/setup-sdk/#http-request-headers 문서로가서 화면 아래로 스크롤을 한뒤, Additional information에서 원하는 것을 선택하면됩니다.

 

9. 마지막으로 클라이언트에서 결제 소스.

제가 구현했던 결제 소스를 남겨 드립니다. 참고하시기 바랍니다.

// npm 모듈들.
const express = require( 'express' );
const paypal = require('@paypal/checkout-server-sdk');







module.exports.init = function(
    _isDebug, _client_id, _secret, _sandbox_client_id, _sandbox_secret
    ){

    //  --- --- --- ---     페이팔 설정 관련 메소드들 입니다.

    // 디버그 인지 여부에 따라 사용할 환경 설정 객체를 반환하는 메소드를 만들어 줍니다.
    let environment = "";

    if( _isDebug == "YES" )
    {

        console.log( "페이팔은 sandbox 모드로 동작합니다." );
        environment = function()
        {
            return new paypal.core.SandboxEnvironment(
                _sandbox_client_id, _sandbox_secret
            );
        }

    }

    else
    {

        console.log( "페이팔은 live 모드로 동작합니다." );
        environment = function()
        {
            return new paypal.core.SandboxEnvironment(
                _client_id, _secret
            );
        }

    }

    // 클라이언트를 설정합니다.
    let client = new paypal.core.PayPalHttpClient( environment() );



    // 영수증 가지고 오는 동작을 하는 메소드 입니다.
    let captureOrder =  async function(orderId) {
        // request = new paypal.orders.OrdersCaptureRequest(orderId);
        request = new paypal.orders.OrdersGetRequest(orderId);

        // request.requestBody({});
        // Call API with your client and get a response for your call
        let response = await client.execute(request);
        // console.log(`Response: ${JSON.stringify(response)}`);
        // If call returns body in response, you can get the deserialized version from the result attribute of the response.
        // console.log(`Capture: ${JSON.stringify(response.result)}`);

        return response;
    }
    
    


    //  --- --- --- ---     메일 라우터 및 전역에서 사용되는 메소드들 입니다.

    let mainRouter = express.Router();




    //  --- --- --- ---     라우터들 입니다.

    // 연결되었는지 확인을 위한 에코 처리를 합니다.
    mainRouter.use( "/echo", function( req, res, next ){

        
        
        // 입력 받은 값을 그대로 반환합니다.
        res.end( req.body.echo );
        return;


    } );


    // 페이팔 영수증 검증.
    mainRouter.use( "/receipt", async function( req, res, next ){


        console.log( req.body );


        // 2a. Get the order ID from the request body
        const orderID = req.body.receipt;
        let capture =  await captureOrder(orderID); 
        

        console.log( capture );


        return res.end("일단 연동 되었음.");


    } )




    //  --- --- --- ---     반환 및 후처리 메소드들 입니다.

    // 결과를 반환합니다.
    return mainRouter;


}
















































// 문서의 끝 입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Posted by 창업닉군
,