Skip to content

Commit 5b3d1c1

Browse files
initial commit
0 parents  commit 5b3d1c1

File tree

17 files changed

+1601
-0
lines changed

17 files changed

+1601
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

README.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Paytm Miniapps Node Client SDK
2+
3+
A node client SDK to interact with Paytm's miniapps ecosystem
4+
5+
## Requirements
6+
7+
Make sure nodejs version **8.17.0 or above** is installed. To check current node version, run
8+
```sh
9+
node -v
10+
```
11+
12+
## Getting Started
13+
14+
* To use it in your code, include following lines in your **package.json**
15+
16+
```javascript
17+
"dependencies": {
18+
...
19+
"paytm-mini-programs-nodejs-sdk": "https://github.com/paytm/paytm-mini-programs-nodejs-sdk.git"
20+
...
21+
}
22+
```
23+
24+
* Install with npm:
25+
26+
```sh
27+
npm install paytm-mini-programs-nodejs-sdk
28+
```
29+
30+
## Usage
31+
32+
### Auth Client
33+
34+
* Configuring Auth client
35+
36+
```javascript
37+
38+
const miniAppsClientSdk = require('paytm-mini-programs-nodejs-sdk');
39+
const OauthClient = miniAppsClientSdk.clients.oauth;
40+
const oauthClient = new OauthClient({
41+
clientId : "<Auth Client ID received on onboarding>"
42+
clientSecret : "<Auth Client Secret received on onboarding>"
43+
},{
44+
ENDPOINT : "https://accounts.paytm.com",
45+
TIMEOUT : 10 * 1000
46+
});
47+
48+
```
49+
50+
* An example of fetch access token
51+
52+
```javascript
53+
54+
(async function() {
55+
try {
56+
const requestOpts = {
57+
code : "<Auth code received from trust login>"
58+
};
59+
const response = await oauthClient.oauthToken(requestOpts);
60+
console.log('Here is oauth token response', JSON.stringify(response));
61+
} catch(err) {
62+
console.log('Some error occurred while fetching oauth token', err);
63+
}
64+
}());
65+
66+
```
67+
68+
* An example of User Profile
69+
70+
```javascript
71+
72+
(async function() {
73+
try {
74+
const requestOpts = {
75+
scopeCode : "<received from fetch access token api response: access_token>"
76+
};
77+
const response = await oauthClient.userProfile(requestOpts);
78+
console.log('Here is user profile response', JSON.stringify(response));
79+
} catch(err) {
80+
console.log('Some error occurred while fetching user profile', err);
81+
}
82+
}());
83+
84+
```
85+
86+
87+
### Miniapps Common Client
88+
89+
* Configuring Common Client
90+
91+
```javascript
92+
93+
const miniAppsClientSdk = require('paytm-mini-programs-nodejs-sdk');
94+
const MiniAppsCommonClient = miniAppsClientSdk.clients.common;
95+
const commonClient = new MiniAppsCommonClient({
96+
clientId : "<Auth Client ID received on onboarding>"
97+
},{
98+
ENDPOINT : "https://miniapps.paytm.com",
99+
TIMEOUT : 10 * 1000
100+
});
101+
102+
```
103+
104+
* An example of fetch open id
105+
106+
```javascript
107+
108+
(async function() {
109+
try {
110+
const sso_token = "<received from fetch access token api response: access_token>";
111+
const response = await commonClient.getPartnerOpenId(sso_token);
112+
console.log('Here is partner open id response', JSON.stringify(response));
113+
} catch(err) {
114+
console.log('Some error occurred while fetching open id', err);
115+
}
116+
}());
117+
118+
```
119+
120+
* An example of send notification
121+
122+
```javascript
123+
124+
(async function() {
125+
try {
126+
const payload = {
127+
name : "<name>",
128+
vertical : "<vertical>",
129+
url : "<url>"
130+
};
131+
132+
const requestObject = {
133+
access_token : "<received from fetch access token: access_token>",
134+
mid : "<merchant mid received on onboarding>",
135+
openId : "<received from fetch open id>",
136+
orderId : "<paytm order id received after placing order>",
137+
templateName : "<notification template name received on onboarding>",
138+
notificationPayload : payload
139+
};
140+
141+
const response = await commonClient.sendPartnerNotification(requestObject);
142+
console.log('Here is send partner notification response', JSON.stringify(response));
143+
} catch(err) {
144+
console.log('Some error occurred while sending partner notification', err);
145+
}
146+
}());
147+
148+
```
149+
150+
## Development
151+
152+
### Getting Started
153+
154+
* Clone this repository
155+
```sh
156+
git clone https://github.com/paytm/paytm-mini-programs-nodejs-sdk.git
157+
```
158+
159+
* Install dependencies
160+
```sh
161+
npm install
162+
```
163+
164+
### Documentation
165+
166+
To generate complete documentation, run
167+
168+
```sh
169+
npm run docs
170+
```
171+
172+
Open the generated document via **./docs/\<repository name\>/\<version\>/index.html**
173+
174+
### Debugging
175+
176+
To view debug logs for this client, run your app with the environment variable **DEBUG=miniapps.node.***
177+
```sh
178+
DEBUG=miniapps.node.* NODE_ENV=staging node app.js
179+
```
180+
181+
### Unit Test Cases
182+
183+
To run unit test cases for this client, use following command :
184+
```sh
185+
npm test
186+
```
187+
188+
### Code Coverage
189+
190+
To generate code coverage for test cases, use following command :
191+
```sh
192+
npm run coverage
193+
```
194+
195+
Open the generated document via **./coverage/index.html**

clients/base.js

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
"use strict";
2+
3+
const requestPromise = require('request-promise');
4+
const debug = require('debug')('miniapps.node.clients.base');
5+
const uuid = require('uuid');
6+
const L = require('../lib').logger;
7+
const LibUtils = require('../lib').utils;
8+
9+
/**
10+
* @class
11+
*/
12+
class Base {
13+
/**
14+
*
15+
* Constructor for our base client class. This class is used to act as a base layer for all HTTP calls. It uses the request promise module to achieve the same. This class is primaraly meant to act as a base class which can be further extended to build clients for third party APIs.
16+
*
17+
* @param {Object} options - Following parameters are supported and can be passed as options :
18+
* @param {String} options.ENDPOINT - Hostname / Endpoint for all our client requests
19+
* @param {Number} [options.TIMEOUT = 20000] - Request timeout (in milliseconds)
20+
* @param {String} [options.CLIENT_NAME = 'BASE-CLIENT'] - Name of our client
21+
* @param {String} [options.LOGTAG = '[clients/base]'] - Tag for logging purposes
22+
*
23+
* @throws {Error} Please note that some input parameters for this class are mandatory and hence
24+
* is being validated within the constructor. Hence it is advised to wrap the object creation for
25+
* this class in a try catch block to catch any synchronous errors being thrown from while creating
26+
* this object.
27+
*
28+
*/
29+
constructor({
30+
ENDPOINT,
31+
TIMEOUT = 20 * 1000,
32+
CLIENT_NAME = 'BASE-CLIENT',
33+
LOGTAG = '[clients/base]',
34+
} = {}) {
35+
this.LOGTAG = LOGTAG;
36+
if (!LibUtils.isValidString(ENDPOINT)) {
37+
const err = new TypeError(`Provided endpoint : ${ENDPOINT} is of invalid type`);
38+
debug(`${this.LOGTAG} : Error :`, err);
39+
throw err;
40+
}
41+
42+
this.ENDPOINT = ENDPOINT;
43+
this.TIMEOUT = TIMEOUT;
44+
this.CLIENT_NAME = CLIENT_NAME;
45+
}
46+
47+
/**
48+
*
49+
* Function which taken in request options and hits HTTP request via requestPromise module. It expects following parameters
50+
*
51+
* @param {Object} requestOpts - the HTTP request opts which is needed to hit the request.
52+
*
53+
* @returns {Promise.<Object|Error>} - Returns a promise which either resolves to the required
54+
* response body or rejects with the corresponding error.
55+
*
56+
* @private
57+
*/
58+
async _hitHttpRequest(requestOpts) {
59+
debug(`${this.LOGTAG} : Going to hit HTTP request with options : ${JSON.stringify(requestOpts)}`);
60+
61+
try {
62+
const response = await requestPromise(requestOpts);
63+
debug(`${this.LOGTAG} : Success Response Body :`, requestOpts && requestOpts.resolveWithFullResponse ? JSON.stringify(response.body) : JSON.stringify(response));
64+
return response;
65+
} catch (err) {
66+
debug(`${this.LOGTAG} : Error occurred while hitting HTTP request with options : ${JSON.stringify(requestOpts)}`, err);
67+
throw (err && err.error) || err;
68+
}
69+
}
70+
71+
/**
72+
*
73+
* Function which taken in apiPath and other parameters to generate the request options for hitting the API request. It expects following input parameters :
74+
*
75+
* @param {String} apiPath - The API path for our client. Ex : /v1/some/sample/route
76+
* @param {Object} requestOpts - Following are supported as the parameters which are needed to hit the request.
77+
* @param {String} requestOpts.method - HTTP method, ex : GET, POST, PUT, DELETE, etc.
78+
* @param {Object} [requestOpts.headers] - Request headers for our HTTP request.
79+
* @param {Object} [requestOpts.body] - Request body for our HTTP request.
80+
* @param {Object} [requestOpts.qs] - Query params for our HTTP request.
81+
* @param {Number} [requestOpts.timeout] - Timeout for our HTTP request.
82+
* @param {...any} [requestOpts.otherRequestOpts] - Any other properties which needs to be included in our HTTP request options.
83+
*
84+
* @returns {Object} Returns a promise which either resolves to the required
85+
* response body or rejects with the corresponding error.
86+
*
87+
* @throws {Error} Please note that some input parameters for this function are mandatory and
88+
* hence is being validated. Hence it is advised to wrap this function call in a try catch block to
89+
* catch any synchronous errors being thrown.
90+
*
91+
* @private
92+
*/
93+
_prepareRequestOpts(apiPath, {
94+
method,
95+
headers,
96+
body,
97+
form,
98+
qs,
99+
timeout,
100+
...otherRequestOpts //jshint ignore:line
101+
} = {}) {
102+
if (!LibUtils.isValidString(apiPath)) {
103+
const err = new TypeError(`Provided API path : ${apiPath} is of invalid type`);
104+
debug(`${this.LOGTAG} : Error :`, err);
105+
throw err;
106+
}
107+
108+
if (!LibUtils.isValidString(method)) {
109+
const err = new TypeError(`Provided HTTP method : ${method} is of invalid type`);
110+
debug(`${this.LOGTAG} : Error :`, err);
111+
throw err;
112+
}
113+
114+
headers = headers || {};
115+
116+
headers['x-http-mapps-client-req-id'] = `${uuid.v4()}`;
117+
headers['x-http-mapps-client-name'] = `${this.CLIENT_NAME.toLowerCase()}`;
118+
119+
return {
120+
url: this.ENDPOINT + apiPath,
121+
method,
122+
headers,
123+
body,
124+
form,
125+
qs,
126+
timeout,
127+
...otherRequestOpts, //jshint ignore:line
128+
};
129+
}
130+
131+
/**
132+
*
133+
* Function which taken in apiPath and httpOpts request options and hits HTTP request. This
134+
* function is meant to be overriden in the child classes of this parent class to exhibit API
135+
* specific input parameters and behaviour. It expects following parameters :
136+
*
137+
* @param {String} apiPath - API path. Ex : /v2/some/sample/route
138+
* @param {Object} [httpOpts = {}] - the HTTP opts which is needed to hit the request.
139+
*
140+
* @returns {Promise.<Object|Error>} Returns a promise which either resolves to the required
141+
* response body or rejects with the corresponding error.
142+
*
143+
* @private
144+
*/
145+
async _with(apiPath, httpOpts) {
146+
try {
147+
if (!LibUtils.isValidString(apiPath)) {
148+
throw new TypeError(`Provided apiPath is not of valid type`);
149+
}
150+
151+
if (LibUtils.isNil(httpOpts)) {
152+
throw new TypeError(`Provided httpOpts is not of valid type`);
153+
}
154+
155+
const requestOpts = this._prepareRequestOpts(apiPath, httpOpts);
156+
const response = await this._hitHttpRequest(requestOpts);
157+
return response;
158+
} catch (err) {
159+
L.error(`${this.LOGTAG} : Error occurred while calling API : ${apiPath} for client : ${this.CLIENT_NAME}`);
160+
L.error(`${this.LOGTAG} : HTTP Options : ${JSON.stringify(httpOpts)}`);
161+
L.error(`${this.LOGTAG} : Error :`, err);
162+
throw err;
163+
}
164+
}
165+
}
166+
167+
module.exports = Base;

0 commit comments

Comments
 (0)