UNPKG

restify-new-nodejs-compatible

Version:
420 lines (325 loc) 11.3 kB
--- title: Client Guide permalink: /docs/client-guide/ --- There are actually three separate clients shipped in restify: * **JsonClient:** sends and expects application/json * **StringClient:** sends url-encoded request and expects text/plain * **HttpClient:** thin wrapper over node's http/https libraries The idea being that if you want to support "typical" control-plane REST APIs, you probably want the `JsonClient`, or if you're using some other serialization (like XML) you'd write your own client that extends the `StringClient`. If you need streaming support, you'll need to do some work on top of the `HttpClient`, as `StringClient` and friends buffer requests/responses. All clients support retry with exponential backoff for getting a TCP connection; they do not perform retries on 5xx error codes like previous versions of the restify client. You can set `retry` to `false` to disable this logic altogether. Also, all clients support a `connectTimeout` field, which is use *on each retry*. The default is not to set a `connectTimeout`, so you end up with the node.js socket defaults. Here's an example of hitting the [Joyent CloudAPI](https://apidocs.joyent.com/cloudapi/): ```js var restify = require('restify-clients'); // Creates a JSON client var client = restify.createJsonClient({ url: 'https://us-east-1.api.joyent.com' }); client.basicAuth('$login', '$password'); client.get('/my/machines', function(err, req, res, obj) { assert.ifError(err); console.log(JSON.stringify(obj, null, 2)); }); ``` As a short-hand, a client can be initialized with a string-URL rather than an options object: ```js var restify = require('restify-clients'); var client = restify.createJsonClient('https://us-east-1.api.joyent.com'); ``` Note that all further documentation refers to the "short-hand" form of methods like `get/put/del` which take a string path. You can also pass in an object to any of those methods with extra params (notably headers): ```js var options = { path: '/foo/bar', headers: { 'x-foo': 'bar' }, retry: { 'retries': 0 }, agent: false }; client.get(options, function(err, req, res) { .. }); ``` If you need to interpose additional headers in the request before it is sent on to the server, you can provide a synchronous callback function as the `signRequest` option when creating a client. This is particularly useful with [node-http-signature](https://github.com/joyent/node-http-signature), which needs to attach a cryptographic signature of selected outgoing headers. If provided, this callback will be invoked with a single parameter: the outgoing `http.ClientRequest` object. ## JsonClient The JSON Client is the highest-level client bundled with restify-clients; it exports a set of methods that map directly to HTTP verbs. All callbacks look like `function(err, req, res, [obj])`, where `obj` is optional, depending on if content was returned. HTTP status codes are not interpreted, so if the server returned 4xx or something with a JSON payload, `obj` will be the JSON payload. `err` however will be set if the server returned a status code >= 400 (it will be one of the restify HTTP errors). If `obj` looks like a `RestError`: ```js { "code": "FooError", "message": "some foo happened" } ``` then `err` gets "upconverted" into a `RestError` for you. Otherwise it will be an `HttpError`. ### createJsonClient(options) ```js var client = restify.createJsonClient({ url: 'https://api.us-east-1.joyent.com', version: '*' }); ``` Options: |Name|Type|Description| |----|----|-----------| |accept|String|Accept header to send| |connectTimeout|Number|Amount of time to wait for a socket| |requestTimeout|Number|Amount of time to wait for the request to finish| |dtrace|Object|node-dtrace-provider handle| |gzip|Object|Will compress data when sent using `content-encoding: gzip`| |headers|Object|HTTP headers to set in all requests| |log|Object|[pino](https://github.com/pinojs/pino) instance| |retry|Object|options to provide to node-retry;"false" disables retry; defaults to 4 retries| |signRequest|Function|synchronous callback for interposing headers before request is sent| |url|String|Fully-qualified URL to connect to| |userAgent|String|user-agent string to use; restify inserts one, but you can override it| |version|String|semver string to set the accept-version| ### get(path, callback) Performs an HTTP get; if no payload was returned, `obj` defaults to `{}` for you (so you don't get a bunch of null pointer errors). ```js client.get('/foo/bar', function(err, req, res, obj) { assert.ifError(err); console.log('%j', obj); }); ``` ### head(path, callback) Just like `get`, but without `obj`: ```js client.head('/foo/bar', function(err, req, res) { assert.ifError(err); console.log('%d -> %j', res.statusCode, res.headers); }); ``` ### post(path, object, callback) Takes a complete object to serialize and send to the server. ```js client.post('/foo', { hello: 'world' }, function(err, req, res, obj) { assert.ifError(err); console.log('%d -> %j', res.statusCode, res.headers); console.log('%j', obj); }); ``` ### put(path, object, callback) Just like `post`: ```js client.put('/foo', { hello: 'world' }, function(err, req, res, obj) { assert.ifError(err); console.log('%d -> %j', res.statusCode, res.headers); console.log('%j', obj); }); ``` ### del(path, callback) `del` doesn't take content, since you know, it should't: ```js client.del('/foo/bar', function(err, req, res) { assert.ifError(err); console.log('%d -> %j', res.statusCode, res.headers); }); ``` ## StringClient `StringClient` is what `JsonClient` is built on, and provides a base for you to write other buffering/parsing clients (like say an XML client). If you need to talk to some "raw" HTTP server, then `StringClient` is what you want, as it by default will provide you with content uploads in `application/x-www-form-url-encoded` and downloads as `text/plain`. To extend a `StringClient`, take a look at the source for `JsonClient`. Effectively, you extend it, and set the appropriate options in the constructor and implement a `write` (for put/post) and `parse` method (for all HTTP bodies), and that's it. ### createStringClient(options) ```js var client = restify.createStringClient({ url: 'https://example.com' }) ``` ### get(path, callback) Performs an HTTP get; if no payload was returned, `data` defaults to `''` for you (so you don't get a bunch of null pointer errors). ```js client.get('/foo/bar', function(err, req, res, data) { assert.ifError(err); console.log('%s', data); }); ``` ### head(path, callback) Just like `get`, but without `data`: ```js client.head('/foo/bar', function(err, req, res) { assert.ifError(err); console.log('%d -> %j', res.statusCode, res.headers); }); ``` ### post(path, object, callback) Takes a complete object to serialize and send to the server. ```js client.post('/foo', { hello: 'world' }, function(err, req, res, data) { assert.ifError(err); console.log('%d -> %j', res.statusCode, res.headers); console.log('%s', data); }); ``` ### put(path, object, callback) Just like `post`: ```js client.put('/foo', { hello: 'world' }, function(err, req, res, data) { assert.ifError(err); console.log('%d -> %j', res.statusCode, res.headers); console.log('%s', data); }); ``` ### del(path, callback) `del` doesn't take content, since you know, it should't: ```js client.del('/foo/bar', function(err, req, res) { assert.ifError(err); console.log('%d -> %j', res.statusCode, res.headers); }); ``` ## HttpClient `HttpClient` is the lowest-level client shipped in restify, and is basically just some sugar over the top of node's http/https modules (with HTTP methods like the other clients). It is useful if you want to stream with restify. Note that the event below is unfortunately named `result` and not `response` (because [Event 'response'](http://nodejs.org/docs/latest/api/all.html#event_response_) is already used). ```js client = restify.createClient({ url: 'http://127.0.0.1' }); client.get('/str/mcavage', function(err, req) { assert.ifError(err); // connection error req.on('result', function(err, res) { assert.ifError(err); // HTTP status code >= 400 res.body = ''; res.setEncoding('utf8'); res.on('data', function(chunk) { res.body += chunk; }); res.on('end', function() { console.log(res.body); }); }); }); ``` Or a write: ```js client.post(opts, function(err, req) { assert.ifError(connectErr); req.on('result', function(err, res) { assert.ifError(err); res.body = ''; res.setEncoding('utf8'); res.on('data', function(chunk) { res.body += chunk; }); res.on('end', function() { console.log(res.body); }); }); req.write('hello world'); req.end(); }); ``` Note that get/head/del all call `req.end()` for you, so you can't write data over those. Otherwise, all the same methods exist as `JsonClient/StringClient`. One wishing to extend the `HttpClient` should look at the internals and note that `read` and `write` probably need to be overridden. ### Proxy There are several options for enabling a proxy for the http client. The following options are available to set a proxy url: ```js // Set the proxy option in the client configuration restify.createClient({ proxy: 'http://127.0.0.1' }); ``` From environment variables: ```sh $ export HTTPS_PROXY = 'https://127.0.0.1' $ export HTTP_PROXY = 'http://127.0.0.1' ``` There is an option to disable the use of a proxy on a url basis or for all urls. This can be enabled by setting an environment variable. Don't proxy requests to any urls ```sh $ export NO_PROXY='*' ``` Don't proxy requests to localhost ```sh $ export NO_PROXY='127.0.0.1' ``` Don't proxy requests to localhost on port 8000 ```sh $ export NO_PROXY='localhost:8000' ``` Don't proxy requests to multiple IPs ```sh $ export NO_PROXY='127.0.0.1, 8.8.8.8' ``` **Note**: The url being requested must match the full hostname in the proxy configuration or NO_PROXY environment variable. DNS lookups are not performed to determine the IP address of a hostname. ### basicAuth(username, password) Since it hasn't been mentioned yet, this convenience method (available on all clients), just sets the `Authorization` header for all HTTP requests: ```js client.basicAuth('mark', 'mysupersecretpassword'); ``` ### Upgrades If you successfully negotiate an Upgrade with the HTTP server, an `upgradeResult` event will be emitted with the arguments `err`, `res`, `socket` and `head`. You can use this functionality to establish a WebSockets connection with a server. For example, using the [watershed](https://github.com/jclulow/node-watershed) library: ```js var ws = new Watershed(); var wskey = ws.generateKey(); var options = { path: '/websockets/attach', headers: { connection: 'upgrade', upgrade: 'websocket', 'sec-websocket-key': wskey, } }; client.get(options, function(err, res, socket, head) { res.once('upgradeResult', function(err2, res2, socket2, head2) { var shed = ws.connect(res2, socket2, head2, wskey); shed.on('text', function(msg) { console.log('message from server: ' + msg); shed.end(); }); shed.send('greetings program'); }); }); ```