Skip to content

Commit a78ae65

Browse files
committed
fix without callback, update readme
1 parent 3ec97d3 commit a78ae65

File tree

7 files changed

+462
-341
lines changed

7 files changed

+462
-341
lines changed

.npmignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,4 @@ coverage
88
.nyc_output
99
.babelrc
1010
.git
11-
gulpfile.js
12-
11+
gulpfile.js

README.md

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,49 +49,68 @@ Codeforces.user.rating({ handle: 'user_handle' } , function (err, data) {
4949

5050
### Methods & Parameters
5151

52+
>Full description of the API can be found on : [Official API Doc](http://codeforces.com/api/help)
53+
54+
| Method | Parameters | Description |
55+
| ----------------------- | ------------------------------------------------------------ |:-------------------------------------------------------------------:|
56+
| blogEntry.comments | *blogEntryId | [More](http://codeforces.com/api/help/methods#blogEntry.comments) |
57+
| blogEntry.view | *blogEntryId | [More](http://codeforces.com/api/help/methods#blogEntry.view) |
58+
| contest.hacks | contestId | [More](http://codeforces.com/api/help/methods#contest.hacks) |
59+
| contest.list | gym | [More](http://codeforces.com/api/help/methods#contest.list) |
60+
| contest.ratingChanges | *contestId | [More](http://codeforces.com/api/help/methods#contest.ratingChanges) |
61+
| contest.standings | *contestId , from , count , handles , room , showUnofficial | [More](http://codeforces.com/api/help/methods#contest.standings) |
62+
| contest.status | *contestId , handle , from , count | [More](http://codeforces.com/api/help/methods#contest.status) |
63+
| problemset.problems | tags | [More](http://codeforces.com/api/help/methods#problemset.problems ) |
64+
| problemset.recentStatus | *count | [More](http://codeforces.com/api/help/methods#problemset.recentStatus) |
65+
| recentActions | *maxCount | [More](http://codeforces.com/api/help/methods#recentActions) |
66+
| user.blogEntries | *handle | [More](http://codeforces.com/api/help/methods#user.blogEntries) |
67+
| user.friends | onlyOnline | [More](http://codeforces.com/api/help/methods#user.friends) |
68+
| user.info | *handles | [More](http://codeforces.com/api/help/methods#user.info) |
69+
| user.ratedList | activeOnly | [More](http://codeforces.com/api/help/methods#user.ratedList) |
70+
| user.rating | *handle | [More](http://codeforces.com/api/help/methods#user.rating) |
71+
| user.status | *handle , from , count | [More](http://codeforces.com/api/help/methods#user.status) |
72+
> *required parameters
73+
74+
#### Note
75+
**handles** and **tags** can be multiple.There are two different ways to set:
76+
1. Semicilon-separated string:
77+
78+
```javascript
79+
tags: 'greedy;dp;graphs'
80+
```
81+
82+
2. As array:
5283

53-
| Method | Parameters | Description |
54-
| ----------------------- | ----------------------------------------------------------- |:-------------------------------------------------------------------:|
55-
| blogEntry.comments | blogEntryId | [More](http://codeforces.com/api/help/methods#blogEntry.comments) |
56-
| blogEntry.view | blogEntryId | [More](http://codeforces.com/api/help/methods#blogEntry.view) |
57-
| contest.hacks | contestId | [More](http://codeforces.com/api/help/methods#contest.hacks) |
58-
| contest.list | gym | [More](http://codeforces.com/api/help/methods#contest.list) |
59-
| contest.ratingChanges | contestId | [More](http://codeforces.com/api/help/methods#contest.ratingChanges) |
60-
| contest.standings | contestId , from , count , handles , room , showUnofficial | [More](http://codeforces.com/api/help/methods#contest.standings) |
61-
| contest.status | contestId , handle , from , count | [More](http://codeforces.com/api/help/methods#contest.status) |
62-
| problemset.problems | tags | [More](http://codeforces.com/api/help/methods#problemset.problems ) |
63-
| problemset.recentStatus | count | [More](http://codeforces.com/api/help/methods#problemset.recentStatus) |
64-
| recentActions | maxCount | [More](http://codeforces.com/api/help/methods#recentActions) |
65-
| user.blogEntries | handle | [More](http://codeforces.com/api/help/methods#user.blogEntries) |
66-
| user.friends | onlyOnline | [More](http://codeforces.com/api/help/methods#user.friends) |
67-
| user.info | handles | [More](http://codeforces.com/api/help/methods#user.info) |
68-
| user.ratedList | activeOnly | [More](http://codeforces.com/api/help/methods#user.ratedList) |
69-
| user.rating | handle | [More](http://codeforces.com/api/help/methods#user.rating) |
70-
| user.status | handle , from , count | [More](http://codeforces.com/api/help/methods#user.status) |
84+
```javascript
85+
tags: ['greedy','dp','graphs']
86+
```
7187

7288

7389
## Authorization
7490

75-
To access data, API key must be needed.To generate API and SECRET KEY visit: http://codeforces.com/settings/api
76-
77-
91+
To access data, API and SECRET key must be needed.To generate API and SECRET KEY visit: [API Settings](http://codeforces.com/settings/api)
92+
93+
7894
## Return Data
7995

80-
All data return as JSON format.For more details about every data format visit: http://codeforces.com/api/help/objects
81-
96+
All data return in JSON format.For full description of data format visit: [Return Objects](http://codeforces.com/api/help/objects)
97+
8298

8399

84100
## Streaming
85101

86102
>
87-
> This feature and example from npm **request** pakages. For more have a look : https://github.com/request/request
103+
> This feature and example from npm **request** package. For more have a look : [Request Package Doc](https://github.com/request/request)
88104
>
89105
90106

91107
You can stream responses to a file stream.When json data is huge, you may need this feature.
92108

93109
```javascript
94110
Codeforces.user.ratedList( parameters, callback ).pipe( fs.createWriteStream('./rateedList.json') );
111+
112+
//version >= 1.0.2 (with or without callback)
113+
Codeforces.user.ratedList( parameters ).pipe( fs.createWriteStream('./ratedList.json') );
95114
```
96115

97116
Also emits response events.

example/es5/api.js

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,35 @@
1-
var Codeforces = require('../../dist/codeforces');
2-
3-
var fs = require('fs');
1+
var fs = require('fs');
2+
var Codeforces = require('../../dist/codeforces');
43

54
var apiKey = process.env.CFK;
65
var apiSecret = process.env.CFS;
76

87
Codeforces.setApis(apiKey, apiSecret);
98

10-
var params = {
11-
contestId: 566,
12-
from: 1,
13-
count: 2,
14-
showUnofficial:true,
15-
handles: 'rng_58;W4yneb0t'
9+
var parameters = {
10+
handles: ['rng_58','W4yneb0t'] //or 'rng_58;W4yneb0t'
1611
};
1712

18-
Codeforces.contest.standings(params,function (err,result) {
19-
20-
if (err) {
13+
Codeforces.user.info(parameters, function (err,data) {
14+
if(err){
2115
return console.log(err);
2216
}
23-
24-
console.log(result);
25-
17+
console.log(data);
18+
console.log('huha');
2619
});
2720

28-
29-
/*.on('data', function(data) {
30-
// decompressed data as it is received
31-
console.log('decoded chunk: ' + data)
32-
})
21+
/*
22+
.on('data', function(data) {
23+
// decompressed data as it is received
24+
console.log('decoded chunk: ' + data)
25+
})
3326
.on('response', function(response) {
3427
// unmodified http.IncomingMessage object
3528
response.on('data', function(data) {
3629
// compressed data as it is received
3730
console.log('received ' + data.length + ' bytes of compressed data')
3831
})
39-
}).pipe(fs.createWriteStream('./files/rate.json'));*/
32+
}).pipe( fs.createWriteStream('./example/files/rate.json') );*/
4033

4134

4235

example/es6/api.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ Codeforces.problemset.recentStatus(params, (err,result) => {
1717
}
1818

1919
console.log(result);
20-
console.log("yes");
21-
2220
});
2321

2422

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codeforces-api",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"description": "Codeforces API Client Library for Node.js",
55
"main": "dist/codeforces.js",
66
"scripts": {

src/codeforces.js

Lines changed: 73 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as _ from "lodash";
44
import moment from 'moment';
55
import qs from 'qs';
66
import randomstring from 'randomstring';
7-
import request from 'request';
7+
import Request from 'request/request';
88
import sha512 from 'crypto-js/sha512';
99

1010

@@ -14,11 +14,11 @@ import sha512 from 'crypto-js/sha512';
1414
class CF {
1515

1616
/**
17-
* Class constructor, It will Set default routes and options,
17+
* Class constructor, It will Set default routes and options
1818
*/
1919
constructor () {
2020

21-
//credentials for api call
21+
//credentials for API call
2222
this.options = {
2323
API_URL: "http://codeforces.com/api",
2424
API_KEY: "",
@@ -63,10 +63,8 @@ class CF {
6363

6464

6565
/**
66-
* Set api and api secret key for authenticate a API request.
67-
*
68-
* @param {string} API_KEY - user api key
69-
* @param {string} API_SECRET - user api secret
66+
* @param {string} API_KEY - user API key
67+
* @param {string} API_SECRET - user API secret
7068
*/
7169
setApis (API_KEY = "", API_SECRET = "") {
7270
this.options.API_KEY = API_KEY;
@@ -75,75 +73,114 @@ class CF {
7573
}
7674

7775

76+
7877
/**
79-
* Main HTTP request function.
8078
* About method and parameters, see official doc - http://codeforces.com/api/help/
8179
*
82-
* @param {string} method - method of API request. [see doc]
83-
* @param {object} params - API url parameters [see doc]
84-
* @param {function} cb - callback function for async request
80+
* @param {string} method - method of API request.
81+
* @param {object} parameters - API url parameters
82+
* @param {function} callback
8583
* @returns {*}
8684
*/
87-
function callApi(method, params, cb) {
85+
function callApi(method, parameters, callback) {
86+
87+
if (typeof parameters === 'undefined') {
88+
throw new Error('undefined is not a valid parameters object.');
89+
}
90+
91+
if( typeof parameters !== 'object' ){
92+
throw new Error('valid parameters object required.');
93+
}
8894

8995
let opts = this.options;
9096

91-
//validate api key
97+
let noCallback = !callback || typeof callback !== 'function';
9298
let noApiKey = typeof opts.API_KEY !== 'string' || opts.API_KEY.length === 0 || typeof opts.API_SECRET !== 'string' || opts.API_SECRET.length === 0;
9399
if( noApiKey ){
94-
return cb(new Error("API key and API secret required.Please set before calling api."));
100+
if( noCallback ){
101+
throw new Error('API key and API secret required.');
102+
}
103+
return callback(new Error("API key and API secret required."));
95104
}
96105

97106
opts.method = method;
98107

99-
//final url of API request
100-
let url = makeApiUrl(opts,params);
101-
108+
//target API url with hashes
109+
let url = makeApiUrl(opts, parameters);
102110

103-
//request config
104-
let requestConfig = {
111+
let reqOptions = {
105112
uri: url,
106113
json: true,
107114
timeout: process.env.CF_TIMEOUT || opts.DEFAULT_TIMEOUT
108115
};
109116

110-
//return request for streaming, some data are so big
111-
return request(requestConfig, function (err,httpResponse,body) {
112-
if(err){
113-
return cb(err);
114-
}
117+
//callback not exists, just return the request modules Request class instance for event
118+
if( noCallback ){
119+
return new Request(reqOptions);
120+
}
115121

116-
//API request failed
117-
if( body.status !== 'OK' ){
118-
return cb(new Error(body.comment));
119-
}
122+
//callback exists, return Request for streaming and handle callback for error handling and custom formatted data
123+
return callRequest(reqOptions, handleCallback.bind(null,callback) );
124+
}
125+
126+
127+
/**
128+
* Handle user callback
129+
*
130+
* @param callback - user callback
131+
* @param err - request errors
132+
* @param httpResponse - request HTTP response
133+
* @param body - request response body
134+
* @returns {*}
135+
*/
136+
function handleCallback(callback, err, httpResponse, body) {
120137

121-
return cb(null,body.result);
122-
});
138+
if(err){
139+
return callback(err);
140+
}
141+
142+
//API returns error
143+
if( body.status !== 'OK' ){
144+
return callback(body.comment);
145+
}
146+
147+
return callback(null, body.result);
148+
}
149+
150+
151+
/**
152+
* Call request modules main class instead of base function
153+
* @param options
154+
* @param callback
155+
* @returns {Request}
156+
*/
157+
function callRequest(options,callback) {
158+
options.callback = callback;
159+
return new Request(options);
123160
}
124161

125162

126163
/**
127164
* Generate API url according to CF API rules
128165
*
129166
* @param {array} options - main class options
130-
* @param {array} params - API url parameters [see doc]
167+
* @param {array} parameters - API url parameters [see doc]
131168
* @returns {string} - final url
132169
*/
133-
function makeApiUrl(options,params) {
170+
function makeApiUrl(options,parameters) {
134171

135172
//main query to add in API url request
136-
let query = params;
173+
let query = parameters;
137174
let curTime = moment().unix();
138175
let randomToken = randomstring.generate(6);
139176

140177
query.time = curTime;
141178
query.apiKey = options.API_KEY;
142179

143180
//if any parameter given as array, make it string separated by semicolon(;)
144-
for(let key in params){
145-
if( _.isArray(params[key]) ){
146-
params[key] = _.join(params[key],';');
181+
for(let key in parameters){
182+
if( _.isArray(parameters[key]) ){
183+
parameters[key] = _.join(parameters[key],';');
147184
}
148185
}
149186

0 commit comments

Comments
 (0)