1 | # node-sdk
|
2 |
|
3 | [![npm version](https://img.shields.io/npm/v/@hexonet/ispapi-apiconnector.svg?style=flat)](https://www.npmjs.com/package/@hexonet/ispapi-apiconnector)
|
4 | [![node](https://img.shields.io/node/v/@hexonet/ispapi-apiconnector.svg)](https://www.npmjs.com/package/@hexonet/ispapi-apiconnector)
|
5 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
|
6 | [![build](https://travis-ci.com/hexonet/node-sdk.svg?branch=master)](https://travis-ci.com/hexonet/node-sdk)
|
7 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
8 | [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hexonet/node-sdk/blob/master/CONTRIBUTING.md)
|
9 |
|
10 | This module is a connector library for the insanely fast HEXONET Backend API. For further informations visit our [homepage](https://www.hexonet.net) and do not hesitate to [contact us](https://www.hexonet.net/contact).
|
11 |
|
12 | ## Resources
|
13 |
|
14 | * [Usage Guide](https://github.com/hexonet/node-sdk/blob/master/README.md#how-to-use-this-module-in-your-project)
|
15 | * [Migration Guide](https://github.com/hexonet/node-sdk/wiki/Migration-Guide)
|
16 | * [SDK Documenation](http://rawgit.com/hexonet/node-sdk/master/docs/typedoc/index.html)
|
17 | * [HEXONET Backend API Documentation](https://github.com/hexonet/hexonet-api-documentation/tree/master/API)
|
18 | * [Release Notes](https://github.com/hexonet/node-sdk/releases)
|
19 | * [Development Guide](https://github.com/hexonet/node-sdk/wiki/Development-Guide)
|
20 |
|
21 | ## Features
|
22 |
|
23 | * Automatic IDN Domain name conversion to punycode (our API accepts only punycode format in commands)
|
24 | * Allows nested associative arrays in API commands to improve for bulk parameters
|
25 | * Connecting and communication with our API
|
26 | * Possibility to use a custom mechanism for debug mode
|
27 | * Several ways to access and deal with response data
|
28 | * Getting the command again returned together with the response
|
29 | * Sessionless communication
|
30 | * Session based communication
|
31 | * Possibility to save API session identifier in PHP session
|
32 | * Configure a Proxy for API communication
|
33 | * Configure a Referer for API communication
|
34 | * High Performance Proxy Setup
|
35 |
|
36 | ## How to use this module in your project
|
37 |
|
38 | We have also a demo app available showing how to integrate and use our SDK. See [here](https://github.com/hexonet/node-sdk-demo).
|
39 |
|
40 | ### Requirements
|
41 |
|
42 | * Installed nodejs/npm. We suggest using [nvm](https://github.com/creationix/nvm).
|
43 |
|
44 | ### NodeJS Version Compatibility
|
45 |
|
46 | | Version | NodeJS |
|
47 | | ------- | ------ |
|
48 | | 4.x and below | >= 4.x |
|
49 | | 5.0.0 - 5.0.1 | >= 7.6.0 |
|
50 | | >= 5.0.2 | >= 8.3.0 |
|
51 | | > 5.5.3 | >= 9.x |
|
52 |
|
53 | ### Installation / Update
|
54 |
|
55 | ```bash
|
56 | npm i @hexonet/ispapi-apiconnector@latest --save
|
57 | ```
|
58 |
|
59 | ### High Performance Proxy Setup
|
60 |
|
61 | Long distances to our main data center in Germany may result in high network latencies. If you encounter such problems, we highly recommend to use this setup, as it uses persistent connections to our API server and the overhead for connection establishments is omitted.
|
62 |
|
63 | #### Step 1: Required Apache2 packages / modules
|
64 |
|
65 | *At least Apache version 2.2.9* is required.
|
66 |
|
67 | The following Apache2 modules must be installed and activated:
|
68 |
|
69 | ```bash
|
70 | proxy.conf
|
71 | proxy.load
|
72 | proxy_http.load
|
73 | ssl.conf # for HTTPs connection to our API server
|
74 | ssl.load # for HTTPs connection to our API server
|
75 | ```
|
76 |
|
77 | #### Step 2: Apache configuration
|
78 |
|
79 | An example Apache configuration with binding to localhost:
|
80 |
|
81 | ```bash
|
82 | <VirtualHost 127.0.0.1:80>
|
83 | ServerAdmin webmaster@localhost
|
84 | ServerSignature Off
|
85 | SSLProxyEngine on
|
86 | ProxyPass /api/call.cgi https://api.ispapi.net/api/call.cgi min=1 max=2
|
87 | <Proxy *>
|
88 | Order Deny,Allow
|
89 | Deny from none
|
90 | Allow from all
|
91 | </Proxy>
|
92 | </VirtualHost>
|
93 | ```
|
94 |
|
95 | After saving your configuration changes please restart the Apache webserver.
|
96 |
|
97 | #### Step 3: Using this setup
|
98 |
|
99 | ```js
|
100 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
|
101 | /* eslint-disable @typescript-eslint/no-var-requires */
|
102 | async function main () {
|
103 | const apiconnector = require('@hexonet/ispapi-apiconnector')
|
104 | const cl = new apiconnector.APIClient()
|
105 | cl.useHighPerformanceConnectionSetup()
|
106 | .useOTESystem()
|
107 | .setCredentials('test.user', 'test.passw0rd')
|
108 | .setRemoteIPAddress('1.2.3.4:80')
|
109 | const r = await cl.request({ COMMAND: 'StatusAccount' })
|
110 | console.log(r.getPlain())
|
111 | }
|
112 | main()
|
113 | ```
|
114 |
|
115 | So, what happens in code behind the scenes? We communicate with localhost (so our proxy setup) that passes the requests to the HEXONET API.
|
116 | Of course we can't activate this setup by default as it is based on Steps 1 and 2. Otherwise connecting to our API wouldn't work.
|
117 |
|
118 | Just in case the above port or ip address can't be used, use function setURL instead to set a different URL / Port.
|
119 | `http://127.0.0.1/api/call.cgi` is the default URL for the High Performance Proxy Setup.
|
120 | e.g. `$cl->setURL("http://127.0.0.1:8765/api/call.cgi");` would change the port. Configure that port also in the Apache Configuration (-> Step 2)!
|
121 |
|
122 | Don't use `https` for that setup as it leads to slowing things down as of the https `overhead` of securing the connection. In this setup we just connect to localhost, so no direct outgoing network traffic using `http`. The apache configuration finally takes care passing it to `https` for the final communication to the HEXONET API.
|
123 |
|
124 | ### Customize Logging / Outputs
|
125 |
|
126 | When having the debug mode activated \HEXONET\Logger will be used for doing outputs.
|
127 | Of course it could be of interest for integrators to look for a way of getting this replaced by a custom mechanism like forwarding things to a 3rd-party software, logging into file or whatever.
|
128 |
|
129 | ```js
|
130 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
|
131 | /* eslint-disable @typescript-eslint/no-var-requires */
|
132 | async function main () {
|
133 | const logger = require('mycustomlogger') // has to extend our logger
|
134 | const apiconnector = require('@hexonet/ispapi-apiconnector')
|
135 | const cl = new apiconnector.APIClient()
|
136 | cl.useOTESystem()
|
137 | .setCredentials('test.user', 'test.passw0rd')
|
138 | .setRemoteIPAddress('1.2.3.4:80')
|
139 | .enableDebugMode()
|
140 | .setCustomLogger(new logger.MyCustomLogger())
|
141 | await cl.request({ COMMAND: 'StatusAccount' })
|
142 | }
|
143 | main()
|
144 | ```
|
145 |
|
146 | NOTE: Find an example for a custom logger class implementation in `src/customlogger.ts`. If you have questions, feel free to open a github issue.
|
147 |
|
148 | ### Usage Examples
|
149 |
|
150 | We provide only documentation and examples for the latest release.
|
151 |
|
152 | #### API response format
|
153 |
|
154 | If you got the API communication working, you will notice that we provide two response formats via this library.
|
155 | a) Plain Format
|
156 | b) Hash Format
|
157 | c) ListHash Format
|
158 |
|
159 | The different response formats can be accessed through the Response object itself that is returned by login, logout and request method:
|
160 |
|
161 | ```js
|
162 | // console.log(r.getPlain())
|
163 | // console.log(r.getHash())
|
164 | // console.log(l.getListHash())
|
165 | ```
|
166 |
|
167 | The plain format represents the API plain response.
|
168 | The hash format represents the API response parsed into a js object.
|
169 | The list format makes sense, if you're working with table libraries based on our list commands and need the hash format parsed into a list format.
|
170 |
|
171 | #### API response codes
|
172 |
|
173 | The API response (a JSON object) provides always two keys: CODE and DESCRIPTION.
|
174 | CODE represents a return code which indicates the following cases:
|
175 | "200" -> The command has been processed successfully by the API
|
176 | "4xx" -> A temporary API error occured, retry later
|
177 | "5xx" -> An API error occured
|
178 |
|
179 | In case of a (temporary) error the DESCRIPTION may provide more details on the reason.
|
180 |
|
181 | The hash format provides a PROPERTY key that covers potential data.
|
182 | The list format provides a LIST key that covers potential data.
|
183 |
|
184 | #### Session based API Communication
|
185 |
|
186 | This example is thought for anyone who builds up his own frontend including user login and logout functionality.
|
187 | See how login and logout works and how the request method depends on the login mechanism!
|
188 | The logout can be done at any time separetely triggered. After logout no further requests reusing the by login returned socketcfg are possible.
|
189 | Note: you have to first finish your requests before doing logout. Running queued requests may fail after logout.
|
190 |
|
191 | ```js
|
192 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
|
193 | /* eslint-disable @typescript-eslint/no-var-requires */
|
194 | async function main () {
|
195 | const apiconnector = require('@hexonet/ispapi-apiconnector')
|
196 | const cl = new apiconnector.APIClient()
|
197 | // Use OT&E system, omitting this points by default to the LIVE system
|
198 | cl.useOTESystem()
|
199 | // Set your user id, here: the OT&E demo user
|
200 | .setCredentials('test.user', 'test.passw0rd')
|
201 | // Set Remote IP Address (in case of IP Filter setting)
|
202 | .setRemoteIPAddress('1.2.3.4:80')
|
203 | // Set a subuser view
|
204 | // cl.setUserView('hexotestman.com');
|
205 |
|
206 | console.log('login ...')
|
207 | let r = await cl.login()
|
208 | // Provide an one time password (active 2FA)
|
209 | // const r = await cl.login('12345678');
|
210 | if (r.getCode() !== 200) { // login failed
|
211 | console.log(`LOGIN FAILED -> ${r.getCode()} ${r.getDescription()}`)
|
212 | return
|
213 | }
|
214 | console.log('LOGIN SUCCEEDED')
|
215 |
|
216 | console.log('request further commands ...')
|
217 | r = await cl.request({
|
218 | COMMAND: 'StatusUser'
|
219 | })
|
220 | console.log(`RESPONSE -> ${r.getCode()} ${r.getDescription()}`)
|
221 |
|
222 | console.log('logout ...')
|
223 | r = await cl.logout()
|
224 | if (r.getCode() !== '200') { // login failed
|
225 | console.log(`LOGOUT FAILED -> ${r.getCode()} ${r.getDescription()}`)
|
226 | return
|
227 | }
|
228 | console.log('LOGOUT SUCCEEDED')
|
229 | }
|
230 | main()
|
231 | ```
|
232 |
|
233 | ##### Create your own frontend app on top
|
234 |
|
235 | If you want to create your own frontend application based on our SDK, you will have to know how you can
|
236 | save APIClient's session configuration data to the nodejs session and how to rebuild a new APIClient
|
237 | instance out of it on next incoming request.
|
238 |
|
239 | After successful login, use `cl.saveSession(req.session)` to save APIClient's session into the nodejs one.
|
240 | This snippet is an example for the expressjs framework where `req` is the incoming ClientRequest and
|
241 | `req.session` the expressjs session instance.
|
242 |
|
243 | In your generic route for making API calls use `cl.reuseSession(req.session)` to rebuild APIClient's session
|
244 | out of the previously saved data.
|
245 |
|
246 | We cannot provide integration examples for part depends on your app itself and your own needs.
|
247 | Still feel free to contact us in case you're stuck.
|
248 |
|
249 | #### Sessionless API Communication
|
250 |
|
251 | In the below example no login / logout procedure is required.
|
252 | This is thought for cases where a user session is not of interest.
|
253 | But in that case you always have to provide user and password accordingly.
|
254 | If you want to build your frontend based on this library, we suggest to base it on the above example.
|
255 |
|
256 | ```js
|
257 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
|
258 | /* eslint-disable @typescript-eslint/no-var-requires */
|
259 | async function main () {
|
260 | const apiconnector = require('@hexonet/ispapi-apiconnector')
|
261 | const cl = new apiconnector.APIClient()
|
262 | // Use OT&E system, omitting this points by default to the LIVE system
|
263 | cl.useOTESystem()
|
264 | // Set your user id, here: the OT&E demo user
|
265 | .setCredentials('test.user', 'test.passw0rd')
|
266 | // Set Remote IP Address (in case of IP Filter setting)
|
267 | .setRemoteIPAddress('1.2.3.4:80')
|
268 | // Set a subuser view
|
269 | // .setUserView('hexotestman.com')
|
270 | // Set a one time password (active 2FA)
|
271 | // .setOTP('12345678')
|
272 |
|
273 | const r = cl.request({
|
274 | COMMAND: 'StatusUser'
|
275 | })
|
276 | console.log(r.getPlain())
|
277 | }
|
278 | main()
|
279 | ```
|
280 |
|
281 | ### Promise based
|
282 |
|
283 | No need to play with async / await.
|
284 |
|
285 | ```js
|
286 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
|
287 | /* eslint-disable @typescript-eslint/no-var-requires */
|
288 | const apiconnector = require('@hexonet/ispapi-apiconnector')
|
289 | const cl = new apiconnector.APIClient()
|
290 | // Use OT&E system, omitting this points by default to the LIVE system
|
291 | cl.useOTESystem()
|
292 | // Set your user id, here: the OT&E demo user
|
293 | cl.setCredentials('test.user', 'test.passw0rd')
|
294 | // Set Remote IP Address (in case of IP Filter setting)
|
295 | cl.setRemoteIPAddress('1.2.3.4:80')
|
296 | // Set a subuser view
|
297 | // cl.setUserView('hexotestman.com');
|
298 | // Set a one time password (active 2FA)
|
299 | // cl.setOTP('12345678');
|
300 |
|
301 | cl.request({
|
302 | COMMAND: 'StatusUser'
|
303 | }).then((r) => {
|
304 | console.log(r.getPlain())
|
305 | })
|
306 | ```
|
307 |
|
308 | ### Use of method chaining
|
309 |
|
310 | Shorten your code by using method chaining
|
311 |
|
312 | ```js
|
313 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
|
314 | /* eslint-disable @typescript-eslint/no-var-requires */
|
315 | const apiconnector = require('@hexonet/ispapi-apiconnector')
|
316 | const cl = new apiconnector.APIClient()
|
317 | cl.useOTESystem()
|
318 | .setCredentials('test.user', 'test.passw0rd')
|
319 | .setRemoteIPAddress('1.2.3.4:80')
|
320 | // .setUserView('hexotestman.com');
|
321 | // .setOTP('12345678');
|
322 |
|
323 | cl.request({
|
324 | COMMAND: 'StatusUser'
|
325 | }).then((r) => {
|
326 | console.log(r.getPlain())
|
327 | })
|
328 | ```
|
329 |
|
330 | ### Use of nested arrays in API command (SINCE v5.6.0)
|
331 |
|
332 | Improve your code by using the below
|
333 |
|
334 | ```js
|
335 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
|
336 | /* eslint-disable @typescript-eslint/no-var-requires */
|
337 | const apiconnector = require('@hexonet/ispapi-apiconnector')
|
338 | const cl = new apiconnector.APIClient()
|
339 | cl.useOTESystem()
|
340 | .setCredentials('test.user', 'test.passw0rd')
|
341 | .setRemoteIPAddress('1.2.3.4:80')
|
342 | // .setUserView('hexotestman.com');
|
343 | // .setOTP('12345678');
|
344 |
|
345 | cl.request({
|
346 | COMMAND: 'QueryDomainOptions',
|
347 | DOMAIN: ['example1.com', 'example2.com']
|
348 | }).then((r) => {
|
349 | console.log(r.getPlain())
|
350 | })
|
351 | ```
|
352 |
|
353 | instead of
|
354 |
|
355 | ```js
|
356 | /* eslint-disable @typescript-eslint/explicit-function-return-type */
|
357 | /* eslint-disable @typescript-eslint/no-var-requires */
|
358 | const apiconnector = require('@hexonet/ispapi-apiconnector')
|
359 | const cl = new apiconnector.APIClient()
|
360 | cl.useOTESystem()
|
361 | .setCredentials('test.user', 'test.passw0rd')
|
362 | .setRemoteIPAddress('1.2.3.4:80')
|
363 | // .setUserView('hexotestman.com');
|
364 | // .setOTP('12345678');
|
365 |
|
366 | cl.request({
|
367 | COMMAND: 'QueryDomainOptions',
|
368 | DOMAIN0: 'example1.com',
|
369 | DOMAIN1: 'example2.com'
|
370 | }).then((r) => {
|
371 | console.log(r.getPlain())
|
372 | })
|
373 | ```
|
374 |
|
375 | The SDK itself will flatten the nested array correctly into expected plain text format before sending it to our API.
|
376 |
|
377 | ## Contributing
|
378 |
|
379 | Please read [our development guide](https://github.com/hexonet/node-sdk/wiki/Development-Guide) for details on our code of conduct, and the process for submitting pull requests to us.
|
380 |
|
381 | ## Authors
|
382 |
|
383 | * **Kai Schwarz** - *lead development* - [PapaKai](https://github.com/papakai)
|
384 |
|
385 | See also the list of [contributors](https://github.com/hexonet/node-sdk/graphs/contributors) who participated in this project.
|
386 |
|
387 | ## License
|
388 |
|
389 | MIT
|