From 3b90b20748aff91fbc4d008d42e4052743ffbd73 Mon Sep 17 00:00:00 2001 From: Niklas Mollenhauer Date: Sat, 28 Jan 2017 15:58:37 +0100 Subject: [PATCH 1/3] Rename old definitions --- needle/v0/index.d.ts | 92 +++++++++++++++++++++++++++++++++ needle/v0/needle-tests.ts | 106 ++++++++++++++++++++++++++++++++++++++ needle/v0/tsconfig.json | 27 ++++++++++ 3 files changed, 225 insertions(+) create mode 100644 needle/v0/index.d.ts create mode 100644 needle/v0/needle-tests.ts create mode 100644 needle/v0/tsconfig.json diff --git a/needle/v0/index.d.ts b/needle/v0/index.d.ts new file mode 100644 index 0000000000..fbeb349c33 --- /dev/null +++ b/needle/v0/index.d.ts @@ -0,0 +1,92 @@ +// Type definitions for needle 0.7.8 +// Project: https://github.com/tomas/needle +// Definitions by: San Chen +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +declare module "needle" { + import * as http from 'http'; + import * as Buffer from 'buffer'; + module Needle { + interface NeedleResponse extends http.IncomingMessage { + body: any; + raw: Buffer; + bytes: number; + } + + interface ReadableStream extends NodeJS.ReadableStream { + } + + interface Callback { + (error: Error, response: NeedleResponse, body: any): void; + } + + interface RequestOptions { + timeout?: number; + follow?: number; + follow_max?: number; + multipart?: boolean; + proxy?: string; + agent?: string; + headers?: Object; + auth?: string; // auto | digest | basic (default) + json?: boolean; + + // These properties are overwritten by those in the 'headers' field + compressed?: boolean; + cookies?: { [name: string]: any; }; + // Overwritten if present in the URI + username?: string; + password?: string; + } + + interface ResponseOptions { + decode?: boolean; + parse?: boolean; + output?: any; + } + + interface TLSOptions { + pfx?: any; + key?: any; + passphrase?: string; + cert?: any; + ca?: any; + ciphers?: any; + rejectUnauthorized?: boolean; + secureProtocol?: any; + } + + interface NeedleStatic { + defaults(options?: any): void; + + head(url: string): ReadableStream; + head(url: string, callback?: Callback): ReadableStream; + head(url: string, options?: RequestOptions, callback?: Callback): ReadableStream; + + get(url: string): ReadableStream; + get(url: string, callback?: Callback): ReadableStream; + get(url: string, options?: RequestOptions, callback?: Callback): ReadableStream; + + post(url: string, data: any): ReadableStream; + post(url: string, data: any, callback?: Callback): ReadableStream; + post(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + + put(url: string, data: any): ReadableStream; + put(url: string, data: any, callback?: Callback): ReadableStream; + put(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + + delete(url: string, data: any): ReadableStream; + delete(url: string, data: any, callback?: Callback): ReadableStream; + delete(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + + request(method: string, url: string, data: any): ReadableStream; + request(method: string, url: string, data: any, callback?: Callback): ReadableStream; + request(method: string, url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + } + } + + var needle: Needle.NeedleStatic; + export = needle; +} diff --git a/needle/v0/needle-tests.ts b/needle/v0/needle-tests.ts new file mode 100644 index 0000000000..5a849ec204 --- /dev/null +++ b/needle/v0/needle-tests.ts @@ -0,0 +1,106 @@ +import needle = require("needle"); + +function Usage() { + // using callback + needle.get('http://ifconfig.me/all.json', function (error, response) { + if (!error) + console.log(response.body.ip_addr); // JSON decoding magic. :) + }); + + // using streams + var out: any; // = fs.createWriteStream('logo.png'); + needle.get('https://google.com/images/logo.png').pipe(out); +} + +function ResponsePipeline() { + needle.get('http://stackoverflow.com/feeds', { compressed: true }, function (err, resp) { + console.log(resp.body); // this little guy won't be a Gzipped binary blob + // but a nice object containing all the latest entries + }); + + var options = { + compressed: true, + follow: 5, + rejectUnauthorized: true + }; + + // in this case, we'll ask Needle to follow redirects (disabled by default), + // but also to verify their SSL certificates when connecting. + var stream = needle.get('https://backend.server.com/everything.html', options); + + stream.on('readable', function () { + var data: any; + while (data = stream.read()) { + console.log(data.toString()); + } + }); +} + +function API_head() { + var options = { + timeout: 5000 // if we don't get a response in 5 seconds, boom. + }; + + needle.head('https://my.backend.server.com', function (err, resp) { + if (err) { + console.log('Shoot! Something is wrong: ' + err.message); + } + else { + console.log('Yup, still alive.'); + } + }); +} + +function API_get() { + needle.get('google.com/search?q=syd+barrett', function (err, resp) { + // if no http:// is found, Needle will automagically prepend it. + }); +} + +function API_post() { + var options = { + headers: { 'X-Custom-Header': 'Bumbaway atuna' } + }; + + needle.post('https://my.app.com/endpoint', 'foo=bar', options, function (err, resp) { + // you can pass params as a string or as an object. + }); +} + +function API_put() { + var nested = { + params: { + are: { + also: 'supported' + } + } + }; + + needle.put('https://api.app.com/v2', nested, function (err, resp) { + console.log('Got ' + resp.bytes + ' bytes.') // another nice treat from this handsome fella. + }); +} + +function API_delete() { + var options = { + username: 'fidelio', + password: 'x' + }; + + needle.delete('https://api.app.com/messages/123', null, options, function (err, resp) { + // in this case, data may be null, but you need to explicity pass it. + }); +} + +function API_request() { + var data = { + q: 'a very smart query', + page: 2, + format: 'json' + }; + + needle.request('get', 'forum.com/search', data, function (err, resp) { + if (!err && resp.statusCode == 200) + console.log(resp.body); // here you go, mister. + }); +} diff --git a/needle/v0/tsconfig.json b/needle/v0/tsconfig.json new file mode 100644 index 0000000000..44c8b59654 --- /dev/null +++ b/needle/v0/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../../" + ], + "paths": { + "needle": [ + "needle/v0" + ] + }, + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "needle-tests.ts" + ] +} From f2189422605944f5acc5ee840b21d952c26f138f Mon Sep 17 00:00:00 2001 From: Niklas Mollenhauer Date: Sat, 28 Jan 2017 16:22:21 +0100 Subject: [PATCH 2/3] Add updated/rewritten definitions for v1 --- needle/index.d.ts | 114 ++++++++++++++++++++------------- needle/needle-tests.ts | 139 ++++++++++++++++++++++++++++++++++++++--- needle/tsconfig.json | 6 +- needle/v0/index.d.ts | 43 +++++-------- 4 files changed, 221 insertions(+), 81 deletions(-) diff --git a/needle/index.d.ts b/needle/index.d.ts index 7607fdfc78..f7e3bc275c 100644 --- a/needle/index.d.ts +++ b/needle/index.d.ts @@ -1,6 +1,6 @@ -// Type definitions for needle 0.7.8 +// Type definitions for needle 1.4 // Project: https://github.com/tomas/needle -// Definitions by: San Chen +// Definitions by: San Chen , Niklas Mollenhauer // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped /// @@ -8,85 +8,111 @@ declare module "needle" { import * as http from 'http'; import * as Buffer from 'buffer'; - module Needle { + import * as https from 'https'; + namespace Needle { interface NeedleResponse extends http.IncomingMessage { body: any; raw: Buffer; bytes: number; } - interface ReadableStream extends NodeJS.ReadableStream { + type ReadableStream = NodeJS.ReadableStream; + + type NeedleCallback = (error: Error, response: NeedleResponse, body: any) => void; + + interface Cookies { + [name: string]: any; } - interface Callback { - (error: Error, response: NeedleResponse, body: any): void; - } + type NeedleOptions = RequestOptions & ResponseOptions & RedirectOptions & https.RequestOptions; interface RequestOptions { + open_timeout?: number; + read_timeout?: number; + /** + * Alias for open_timeout + */ timeout?: number; - follow?: number; + follow_max?: number; + /** + * Alias for follow_max + */ + follow?: number; + multipart?: boolean; + agent?: http.Agent | boolean; proxy?: string; - agent?: string; - headers?: Object; - auth?: string; // auto | digest | basic (default) + headers?: {}; + auth?: "auto" | "digest" | "basic"; json?: boolean; // These properties are overwritten by those in the 'headers' field + cookies?: Cookies; compressed?: boolean; - cookies?: { [name: string]: any; }; // Overwritten if present in the URI username?: string; password?: string; + accept?: string; + connection?: string; + user_agent?: string; } interface ResponseOptions { + decode_response?: boolean; + /** + * Alias for decode_response + */ decode?: boolean; + parse_response?: boolean; + /** + * Alias for parse_response + */ parse?: boolean; - output?: any; + + parse_cookies?: boolean; + output?: string; } - interface TLSOptions { - pfx?: any; - key?: any; - passphrase?: string; - cert?: any; - ca?: any; - ciphers?: any; - rejectUnauthorized?: boolean; - secureProtocol?: any; + interface RedirectOptions { + follow_set_cookie?: boolean; + follow_set_referer?: boolean; + follow_keep_method?: boolean; + follow_if_same_host?: boolean; + follow_if_same_protocol?: boolean; } + interface KeyValue { + [key: string]: any; + } + + type BodyData = Buffer | KeyValue | NodeJS.ReadableStream | string | null; + interface NeedleStatic { - defaults(options?: any): void; + defaults(options: NeedleOptions): void; - head(url: string): ReadableStream; - head(url: string, callback?: Callback): ReadableStream; - head(url: string, options?: RequestOptions, callback?: Callback): ReadableStream; + head(url: string, callback?: NeedleCallback): ReadableStream; + head(url: string, options?: NeedleOptions, callback?: NeedleCallback): ReadableStream; - get(url: string): ReadableStream; - get(url: string, callback?: Callback): ReadableStream; - get(url: string, options?: RequestOptions, callback?: Callback): ReadableStream; + get(url: string, callback?: NeedleCallback): ReadableStream; + get(url: string, options?: NeedleOptions, callback?: NeedleCallback): ReadableStream; - post(url: string, data: any): ReadableStream; - post(url: string, data: any, callback?: Callback): ReadableStream; - post(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + post(url: string, data: BodyData, callback?: NeedleCallback): ReadableStream; + post(url: string, data: BodyData, options?: NeedleOptions, callback?: NeedleCallback): ReadableStream; - put(url: string, data: any): ReadableStream; - put(url: string, data: any, callback?: Callback): ReadableStream; - put(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + put(url: string, data: BodyData, callback?: NeedleCallback): ReadableStream; + put(url: string, data: BodyData, options?: NeedleOptions, callback?: NeedleCallback): ReadableStream; - delete(url: string, data: any): ReadableStream; - delete(url: string, data: any, callback?: Callback): ReadableStream; - delete(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + patch(url: string, data: BodyData, callback?: NeedleCallback): ReadableStream; + patch(url: string, data: BodyData, options?: NeedleOptions, callback?: NeedleCallback): ReadableStream; - request(method: string, url: string, data: any): ReadableStream; - request(method: string, url: string, data: any, callback?: Callback): ReadableStream; - request(method: string, url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + delete(url: string, data: BodyData, callback ?: NeedleCallback): ReadableStream; + delete(url: string, data: BodyData, options ?: NeedleOptions, callback ?: NeedleCallback): ReadableStream; + + request(method: string, url: string, data: BodyData, callback?: NeedleCallback): ReadableStream; + request(method: string, url: string, data: BodyData, options?: NeedleOptions, callback?: NeedleCallback): ReadableStream; } } - - var needle: Needle.NeedleStatic; + const needle: Needle.NeedleStatic; export = needle; -} \ No newline at end of file +} diff --git a/needle/needle-tests.ts b/needle/needle-tests.ts index 3df14952c3..1c5090027a 100644 --- a/needle/needle-tests.ts +++ b/needle/needle-tests.ts @@ -1,4 +1,5 @@ -import needle = require("needle"); +import * as needle from "needle"; +import * as fs from "fs"; function Usage() { // using callback @@ -14,7 +15,7 @@ function Usage() { function ResponsePipeline() { needle.get('http://stackoverflow.com/feeds', { compressed: true }, function (err, resp) { - console.log(resp.body); // this little guy won't be a Gzipped binary blob + console.log(resp.body); // this little guy won't be a Gzipped binary blob // but a nice object containing all the latest entries }); @@ -24,21 +25,26 @@ function ResponsePipeline() { rejectUnauthorized: true }; - // in this case, we'll ask Needle to follow redirects (disabled by default), + // in this case, we'll ask Needle to follow redirects (disabled by default), // but also to verify their SSL certificates when connecting. var stream = needle.get('https://backend.server.com/everything.html', options); stream.on('readable', function () { var data: any; - while (data = this.read()) { + while (data = stream.read()) { console.log(data.toString()); } }); + + stream.on('end', function(err: any) { + // if our request had an error, our 'end' event will tell us. + if (!err) console.log('Great success!'); + }) } function API_head() { var options = { - timeout: 5000 // if we don't get a response in 5 seconds, boom. + open_timeout: 5000 // if we don't get a response in 5 seconds, boom. }; needle.head('https://my.backend.server.com', function (err, resp) { @@ -93,14 +99,131 @@ function API_delete() { } function API_request() { - var data = { + var params = { q: 'a very smart query', page: 2, - format: 'json' }; - needle.request('get', 'forum.com/search', data, function (err, resp) { + needle.request('get', 'forum.com/search', params, function (err, resp) { if (!err && resp.statusCode == 200) console.log(resp.body); // here you go, mister. }); + + needle.request('get', 'forum.com/search', params, { json: true }, function(err, resp) { + if (resp.statusCode == 200) console.log('It worked!'); + }); +} + +function HttpGetWithBasicAuth() { + needle.get('https://api.server.com', { username: 'you', password: 'secret' }, function(err, resp) { + // used HTTP auth + }); + needle.get('https://username:password@api.server.com', function(err, resp) { + // used HTTP auth from URL + }); +} + +function DigestAuth() { + needle.get('other.server.com', { username: 'you', password: 'secret', auth: 'digest' }, function(err, resp, body) { + // needle prepends 'http://' to your URL, if missing + }); +} + +function CustomAcceptHeaderDeflate() { + var options = { + compressed: true, + follow: 10, + accept: 'application/vnd.github.full+json' + } + + needle.get('api.github.com/users/tomas', options, function(err, resp, body) { + // body will contain a JSON.parse(d) object + // if parsing fails, you'll simply get the original body + }); + +} + +function Various() { + + needle.get('https://news.ycombinator.com/rss', function(err, resp, body) { + // if xml2js is installed, you'll get a nice object containing the nodes in the RSS + }); + needle.get('http://upload.server.com/tux.png', { output: '/tmp/tux.png' }, function(err, resp, body) { + // you can dump any response to a file, not only binaries. + }); + needle.get('http://search.npmjs.org', { proxy: 'http://localhost:1234' }, function(err, resp, body) { + // request passed through proxy + }); + const stream1 = needle.get('http://www.as35662.net/100.log'); + stream1.on('readable', function() { + let chunk: any; + while (chunk = stream1.read()) { + console.log('got data: ', chunk); + } + }); + const stream2 = needle.get('http://jsonplaceholder.typicode.com/db', { parse: true }); + stream2.on('readable', function() { + let node: any; + + // our stream2 will only emit a single JSON root node. + while (node = stream2.read()) { + console.log('got data: ', node); + } + }); + + /* + // Sample omitted, no JSONStream + needle.get('http://jsonplaceholder.typicode.com/db', { parse: true }) + .pipe(new JSONStream.parse('posts.*.title')) + .on('data', function (obj) { + console.log('got post title: %s', obj); + }); + */ +} + +function FileUpload() { + var data = { + foo: 'bar', + image: { file: '/home/tomas/linux.png', content_type: 'image/png' } + }; + + needle.post('http://my.other.app.com', data, { multipart: true }, function(err, resp, body) { + // needle will read the file and include it in the form-data as binary + }); + needle.put('https://api.app.com/v2', fs.createReadStream('myfile.txt'), function(err, resp, body) { + // stream content is uploaded verbatim + }); +} + +function Multipart() { + var buffer = fs.readFileSync('/path/to/package.zip'); + + var data = { + zip_file: { + buffer: buffer, + filename: 'mypackage.zip', + content_type: 'application/octet-stream' + } + } + + needle.post('http://somewhere.com/over/the/rainbow', data, { multipart: true }, function(err, resp, body) { + // if you see, when using buffers we need to pass the filename for the multipart body. + // you can also pass a filename when using the file path method, in case you want to override + // the default filename to be received on the other end. + }); +} + +function MultipartContentType() { + var data = { + token: 'verysecret', + payload: { + value: JSON.stringify({ title: 'test', version: 1 }), + content_type: 'application/json' + } + } + + needle.post('http://test.com/', data, { timeout: 5000, multipart: true }, function(err, resp, body) { + // in this case, if the request takes more than 5 seconds + // the callback will return a [Socket closed] error + }); } diff --git a/needle/tsconfig.json b/needle/tsconfig.json index 5af602dd4f..59f9b2b49e 100644 --- a/needle/tsconfig.json +++ b/needle/tsconfig.json @@ -5,8 +5,8 @@ "es6" ], "noImplicitAny": true, - "noImplicitThis": false, - "strictNullChecks": false, + "noImplicitThis": true, + "strictNullChecks": true, "baseUrl": "../", "typeRoots": [ "../" @@ -19,4 +19,4 @@ "index.d.ts", "needle-tests.ts" ] -} \ No newline at end of file +} diff --git a/needle/v0/index.d.ts b/needle/v0/index.d.ts index fbeb349c33..28b5b8119f 100644 --- a/needle/v0/index.d.ts +++ b/needle/v0/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for needle 0.7.8 +// Type definitions for needle 0.7 // Project: https://github.com/tomas/needle // Definitions by: San Chen // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped @@ -8,19 +8,16 @@ declare module "needle" { import * as http from 'http'; import * as Buffer from 'buffer'; - module Needle { + namespace Needle { interface NeedleResponse extends http.IncomingMessage { body: any; raw: Buffer; bytes: number; } - interface ReadableStream extends NodeJS.ReadableStream { - } + type ReadableStream = NodeJS.ReadableStream; - interface Callback { - (error: Error, response: NeedleResponse, body: any): void; - } + type NeedleCallback = (error: Error, response: NeedleResponse, body: any) => void; interface RequestOptions { timeout?: number; @@ -29,7 +26,7 @@ declare module "needle" { multipart?: boolean; proxy?: string; agent?: string; - headers?: Object; + headers?: {}; auth?: string; // auto | digest | basic (default) json?: boolean; @@ -61,29 +58,23 @@ declare module "needle" { interface NeedleStatic { defaults(options?: any): void; - head(url: string): ReadableStream; - head(url: string, callback?: Callback): ReadableStream; - head(url: string, options?: RequestOptions, callback?: Callback): ReadableStream; + head(url: string, callback?: NeedleCallback): ReadableStream; + head(url: string, options?: RequestOptions, callback?: NeedleCallback): ReadableStream; - get(url: string): ReadableStream; - get(url: string, callback?: Callback): ReadableStream; - get(url: string, options?: RequestOptions, callback?: Callback): ReadableStream; + get(url: string, callback?: NeedleCallback): ReadableStream; + get(url: string, options?: RequestOptions, callback?: NeedleCallback): ReadableStream; - post(url: string, data: any): ReadableStream; - post(url: string, data: any, callback?: Callback): ReadableStream; - post(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + post(url: string, data: any, callback?: NeedleCallback): ReadableStream; + post(url: string, data: any, options?: RequestOptions, callback?: NeedleCallback): ReadableStream; - put(url: string, data: any): ReadableStream; - put(url: string, data: any, callback?: Callback): ReadableStream; - put(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + put(url: string, data: any, callback?: NeedleCallback): ReadableStream; + put(url: string, data: any, options?: RequestOptions, callback?: NeedleCallback): ReadableStream; - delete(url: string, data: any): ReadableStream; - delete(url: string, data: any, callback?: Callback): ReadableStream; - delete(url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + delete(url: string, data: any, callback?: NeedleCallback): ReadableStream; + delete(url: string, data: any, options?: RequestOptions, callback?: NeedleCallback): ReadableStream; - request(method: string, url: string, data: any): ReadableStream; - request(method: string, url: string, data: any, callback?: Callback): ReadableStream; - request(method: string, url: string, data: any, options?: RequestOptions, callback?: Callback): ReadableStream; + request(method: string, url: string, data: any, callback?: NeedleCallback): ReadableStream; + request(method: string, url: string, data: any, options?: RequestOptions, callback?: NeedleCallback): ReadableStream; } } From 16e6ab0e7d33a2e8056c9af8d266952d89c3249f Mon Sep 17 00:00:00 2001 From: Niklas Mollenhauer Date: Mon, 30 Jan 2017 20:00:48 +0100 Subject: [PATCH 3/3] Remove spaces --- needle/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/needle/index.d.ts b/needle/index.d.ts index f7e3bc275c..8cc61f2a2f 100644 --- a/needle/index.d.ts +++ b/needle/index.d.ts @@ -106,8 +106,8 @@ declare module "needle" { patch(url: string, data: BodyData, callback?: NeedleCallback): ReadableStream; patch(url: string, data: BodyData, options?: NeedleOptions, callback?: NeedleCallback): ReadableStream; - delete(url: string, data: BodyData, callback ?: NeedleCallback): ReadableStream; - delete(url: string, data: BodyData, options ?: NeedleOptions, callback ?: NeedleCallback): ReadableStream; + delete(url: string, data: BodyData, callback?: NeedleCallback): ReadableStream; + delete(url: string, data: BodyData, options?: NeedleOptions, callback ?: NeedleCallback): ReadableStream; request(method: string, url: string, data: BodyData, callback?: NeedleCallback): ReadableStream; request(method: string, url: string, data: BodyData, options?: NeedleOptions, callback?: NeedleCallback): ReadableStream;