Nostalgic Primordial Monster

    @carbon-io/carbon-client-node

    0.7.1 • Public • Published

    Build Status

    CarbonClient


    Overview

    CarbonClient is the client-component for Carbon.io. It is a light-weight RESTFul client For NodeJS that can connect to any REST API. It uses the standard node request module to make http calls.

    Main features:

    • Support for all HTTP methods: GET, PUT, POST, CREATE, DELETE, HEAD, OPTIONS, PATCH.
    • Support for all Carbon.io collections endpoint methods: find(), insert(), update(), findObject(), updateObject(), saveObject(), remove(), removeObject().
    • Asynchronous/synchronous programming styles.
    • Authentication

    Installation

    <path-to-your-app>/
        package.json
    

    Your package.json should include carbon-client-node

    {
        ...
    
        "dependencies": {
            "@carbon-io/carbon-client-node": "git+ssh://git@github.com/carbon-io/carbon-client-node.git"
        }
    
        ...
    }

    Then install the package dependencies like this:

    % cd <path-to-your-app>
    % npm install .
    

    Quick Start

    This is a simple example for an http get operation

    // require the client
    var CarbonClient = require('@carbon-io/carbon-client-node')
    
    // Service for this example: https://github.com/carbon-io/example__hello-world-service/blob/master/lib/HelloService.js
    
    // create the client object
    var client = new CarbonClient("http://localhost:8888")
    
    // GET http://localhost:8888/hello
    client.getEndpoint("hello").get(function(e, response) {
      console.log("Response from /hello: ")
      console.log(response.body)
    })

    Quick Start (synchronized style)

    In general, all CarbonClient methods that take a callback function can be invoked synchronously (within a fiber) by simply not passing a callback function (which is always the last argument). That's the general rule.

    // This example uses the carbon-io fibers module to create a fiber.
    // For more info, see https://docs.carbon.io/en/latest/packages/carbon-core/docs/packages/fibers/docs/guide/index.html
    
    var __ = require('@carbon-io/fibers').__(module)
    
    // require the client
    var CarbonClient = require('@carbon-io/carbon-client-node')
    
    // Service for this example: https://github.com/carbon-io/example__hello-world-service/blob/master/lib/HelloService.js
    
    __(
      function() {
        var client = new CarbonClient("http://localhost:8888")
    
        // Synchronized call, not how
        var response = client.getEndpoint("hello").get()
        console.log("Response from /hello: ")
        console.log(response.body)
    
      })

    Use

    Basic HTTP calls

    All http methods are supported through Endpoint object. Each http method has a matching Endpoint method with same name all lowercase. e.g. GET is done by Endpoint.get(), POST with Endpoint.post(), etc...

    GET

    Supported calling forms for Endpoint.get() are as follows:

    • get(cb)
    • get(options, cb)

    For synchronized calls:

    • get()
    • get(options)
    // require the client
    var CarbonClient = require('@carbon-io/carbon-client-node')
    
    var client = new CarbonClient("http://localhost:8888")
    
    // Service for this example: https://github.com/carbon-io/example__hello-world-service/blob/master/lib/HelloService.js
    
    // create an endpoint object for /hello
    endpoint = client.getEndpoint("hello")
    
    // call get() which will call GET on http://localhost:8888/hello
    endpoint.get(function(e, response) {
      console.log("Response from /hello: ")
      console.log(response.body)
    })

    Response object

    The response object that is returned by CarbonClient is the response object from the nodejs request module. Full doc here https://github.com/request/request

    Some available fields are:

    response.statusCode: http status code (int)
    response.headers: an object containing response headers
    response.body: response body

    Passing query string params

    Query string params are passed as an object through the options.params argument of each http method

    // require the client
    var CarbonClient = require('@carbon-io/carbon-client-node')
    
    // Service for this example: https://github.com/carbon-io/example__hello-world-service-parameter-parsing/blob/master/lib/HelloService.js
    
    var client = new CarbonClient("http://localhost:8888")
    
    // create an endpoint object for /hello
    var endpoint = client.getEndpoint("hello")
    
    var options = {
      params: {
        message: "Welcome to carbon-io!"
    
      }
    }
    
    // GET http://localhost:8888/hello?message="Welcome to carbon-io!"
    endpoint.get(options, function(e, response) {
      console.log("Response from /hello: ")
      console.log(response.body)
    })

    Output:

    Response from /hello:
    { msg: 'Hello world! Welcome to carbon-io!' }
    

    POST

    Supported calling forms for Endpoint.post() are as follows:

    • post(cb)
    • post(body, cb)
    • post(body, options, cb)

    For synchronized calls:

    • post()
    • post(body)
    • post(body, options)
    // require the client
    var CarbonClient = require('@carbon-io/carbon-client-node')
    
    // Service for this example: https://github.com/carbon-io/examples/blob/master/hello-world/HelloService.js
    
    var client = new CarbonClient("http://localhost:8888")
    
    // create an endpoint object for /hello
    var endpoint = client.getEndpoint("hello")
    
    var body = {
      msg: "Welcome to carbon-io!"
    }
    
    endpoint.post(body, function(e, response) {
      console.log("Response from /hello: ")
      console.log(response.body)
    })

    PUT/PATCH

    PUT, PATCH can be performed with Endpoint.put(), Endpoint.patch() methods respectively. Arguments of these methods are all the same and similar to the Endpoint.post() method.

    //  put to /users
    client.getEndpoint("users").put({
        "id": 1234,
        "name": "bob"
      },
      function(e, response) {
        console.log("Response from /users:")
        console.log(response.body)
    })

    HEAD/OPTIONS/DELETE

    HEAD, OPTIONS, DELETE can be performed with Endpoint.head(), Endpoint.options(), Endpoint.delete() methods respectively. Arguments of these methods are all the same and similar to the Endpoint.get() method.

    Supported calling forms for Endpoint.head() are as follows:

    • head(cb)
    • head(options, cb)

    For synchronized calls:

    • head()
    • head(options)
    //  call http OPTIONS method
    client.getEndpoint("test-options").options(null,
      function(e, response) {
        console.log("Response from /test-options:")
        console.log(response.body)
    })

    Collections and Cursors

    CarbonClient provides convenient interfaces to access collections. It provides classes similar to MongoDB Driver Collection/Cursor classes. You can perform find(), insert(), update(), findObject(), updateObject(), saveObject(), remove(), removeObject().

    find()

    The find() method returns a Cursor object which is used to iterate over results.

    find() supports the following calling forms

    • find(query)
    • find(query, options)
    // find all users
    var usersCollection = client.getCollection("users")
    usersCollection.find().toArray(function(e, data) {
      console.log("All users")
      console.log(data)
    })
    
    // find by query
    usersCollection.find({"name": "joe"}).toArray(function(e, data) {
      console.log("All users matching name 'joe'")
      console.log(data)
    })
    
    })

    The find() method returns a Cursor object which is used to iterate over results.

    Cursor iteration

    The Cursor.toArray() loads all results into a single array object which could be memory consuming. To avoid that, use the Cursor.each() method which takes a function to iterate over each item of results. It will return null when the cursor finishes.

    // find all users
    var usersCollection = client.getCollection("users")
    var cursor = usersCollection.find()
    cursor.each(function(e, item) {
      if (item == null) {
        console.log("Finish!")
      } else {
         console.log(item)
      }
    
    
    })

    Cursors also provide a next() method to iterate over a single item. It will return null when the cursor finishes.

    // find all users
    var usersCollection = client.getCollection("users")
    var cursor = usersCollection.find()
    cursor.next(function(e, item) {
      if (item == null) {
        console.log("Finish!")
      } else {
        console.log("Next item:")
        console.log(item)
      }
    
    })
    Cursor pagination

    Pagination for results returned by find() can be achieved with skip and limit options through the options argument:

    var usersCollection = client.getCollection("users")
    var cursor = usersCollection.find({}, {skip:100, limit:100}).toArray(function(e, data) {
      for( var i=0; i < data.length; i++) {
         console.log(data[i])
      }
    
    })
    Sorting find() results

    options argument also allows sort which takes a key to sort on:

    var usersCollection = client.getCollection("users")
    
    // find all users sort by name descending
    var cursor = usersCollection.find({}, {sort:{"name": -1}}).toArray(function(e, data) {
      for( var i=0; i < data.length; i++) {
         console.log(data[i])
      }
    
    })
    Limiting fields within find() results

    You can limit the set of fields returned by find using options.projection argument. The projection argument can be specified in the following form:

    
    {
      <field-path>: 0 | 1
    }
    
    

    set field value to be 1 to include, 0 to exclude.

    var usersCollection = client.getCollection("users")
    
    // find all users and get _id and name, address.city only
    usersCollection.find({}, {
        projection: {
          _id: 1,
          "name": 1,
          "address.city": 1
        }
       }).toArray(function(e, data) {
      for(var i=0; i < data.length; i++) {
         console.log(data[i])
      }
    
    })
    
    // exclude "address" only
    
    // find all users and get _id and name, address.city only
    usersCollection.find({}, {
        projection: {
          "address": 0
        }
       }).toArray(function(e, data) {
      for(var i=0; i < data.length; i++) {
         console.log(data[i])
      }
    
    })

    findObject()

    Finds the object with the specified object id.

    Supported calling forms:

    • findObject(id, cb)

    For synchronized calls:

    • findObject(id)

    insert()

    Supported calling forms:

    • insert(obj, cb)

    For synchronized calls:

    • insert(obj)
    usersCollection.insert({
        username: "joe"
      },
      function(e, result) {
        assert(result.ok) // true for success
        console.log(result)
      }
    )

    update()

    Supported calling forms:

    • update(query, obj, cb)
    • update(query, obj, options, cb)

    For synchronized calls:

    • update(query, obj)
    • update(query, obj, options)

    updateObject()

    Supported calling forms:

    • updateObject(id, update, cb)

    For synchronized calls:

    • updateObject(id, update)

    saveObject()

    Supported calling forms:

    • saveObject(id, obj, cb)

    For synchronized calls:

    • saveObject(id, obj)

    remove()

    Supported calling forms:

    • remove(query, cb)
    • remove(query, options, cb)

    For synchronized calls:

    • remove(query)
    • remove(query, options)

    removeObject()

    Supported calling forms:

    • removeObject(id, cb)

    For synchronized calls:

    • removeObject(id)

    Error handling

    Errors raised by CarbonClient are instances of the HttpError class defined in HttpErrors module of carbon. An HttpError contains the http error code, message, and description.

    For asynchronous calls, The error object will be the first argument of the callback function.

    // GET http://localhost:8888/doesnotexit
    client.getEndpoint("doesnotexit").get(function(e, response) {
      if(e) {
          console.log("Caught an error")
          console.log("code: " + e.code); // 404
          console.log("message: " + e.message);
          console.log("description: " + e.description);
      }
    })

    Synchronized calls (calling with no callbacks)

    It is super easy to make sync calls with CarbonClient. All you have do is just call same methods but just without passing a callback function. Sync calls must be made withing a fiber. The main difference is that the results returned by the method and if there was an error, then it will be raised.

    // This example uses the carbon-io fibers module to create a fiber.
    // For more info, https://docs.carbon.io/en/latest/packages/carbon-core/docs/packages/fibers/docs/guide/index.html
    var __ = require('@carbon-io/fibers').__(module)
    
    var CarbonClient = require('carbon-client-node')
    Synchronized HTTP Methods
    __(
      function() {
    
        // sync get /hello
        var endpoint = client.getEndpoint("hello")
        var res = endpoint.get()
        console.log("Response from /hello:")
        console.log(res.body)
    
    
        // sync post /user
        var usersEndpoint = client.getEndpoint("users")
        var res = usersEndpoint.post({"name": "bob"})
        console.log("Response from /users:")
        console.log(res.body)
    
    })
    Synchronized Collection Methods

    Example for sync Collection.insert() method

    __(
      function() {
        // sync insert
        var result = client.getCollection("users").insert({
                username: "joe"
          })
    
    
        console.log(result.ok)
    })
    Synchronized Cursor Methods
    __(
      function() {
        // sync collection find
        users = client.getCollection("users").find().toArray()
        console.log(users[0])
    })
    

    To use a sync version Cursor.each(), you use the Cusor.eachSync() method for that

    __(
      function() {
    
    
        // sync collection each
        client.getCollection("users").find().eachSync(function(e, item) {
            console.log(item)
        })
    })

    Example for sync Cursor.next() method

    __(
      function() {
        // return the first user
    
        user = client.getCollection("users").find().next()
        console.log(user)
    
        // sync insert
    })
    Error Handling for Synchronized Methods
    __(
      function() {
        // Error handling
        // GET http://localhost:8888/doesnotexit
    
        try {
            client.getEndpoint("doesnotexit").get()
        } catch(e) {
            console.log("Caught an error")
            console.log("code: " + e.code); // 404
            console.log("message: " + e.message);
            console.log("description: " + e.description);
        }
    
      }
    )
    

    Endpoint Tree

    As a convenience, Endpoint allow accessing sub-endpoints using the Endpoint.getEndpoint() method. You can also access the parent Endpoint by Endpoint.parent

    e1 = client.getEndpoint("foo/bar")
    //is equivalent to
    e2 = client.getEndpoint("foo").getEndpoint("bar")

    Endpoint full uri and absolute path can be accessed as follows

    console.log(e1.getAbsolutePath()) // '/foo/bar'
    console.log(e2.getAbsolutePath()) // '/foo/bar' as well
    
    
    console.log(e1.getFullUrl()) // this will return client.uri + endpoint's absolute path which will be http://localhost:8888/foo/bar in this case

    Passing Headers

    Headers can be passed as JSON with the options.headers option. This can be client-level or operation-level. This is an example of an operation-level header passing.

     // Plain text
     client.getEndpoint("hello").get({headers: {"Cache-Control": "no-cache"}},
         function(e, response) {
           console.log("Response from /hello: " + response.body)
       }
     )

    Options

    Options can be be set at client-level or operation-level.

    To set options at the client level, it is passed with the "options" constructor argument CarbonClient(url, options). For passing them on the operation-level, it is passed with the "options" argument for each endpoint http method.

    //e.g
    endpoint.get(options, cb)

    Supported options are as follows:

    Authentication

    Currently, CarbonClient only supports api-key authentication model. CarbonClient allows Api key authentication by passing the api key value in the header or query string. This will make the client send the api key parameter in every request. See following example:

    var client = new CarbonClient("http://localhost:8888", {
      authentication: {
        type: "api-key",
        apiKey:"123",
        apiKeyParameterName: "API_KEY", // the parameter name of the api key
        apiKeyLocation: "header" // use "query" for passing API_KEY using query string
      }
    })
    
    SSL Options

    SSL options are as follows:

    strictSSL: If true, requires SSL certificates be valid
    cert: cert file content
    key: key file content
    ca: ca file content
    

    Here is an example of that

    var defaultOptions = {
      cert: fs.readFileSync("/etc/myservice.cert.pem"),
      key: fs.readFileSync("/etc/myservice.key.pem"),
      ca: caFile ? fs.readFileSync("/etc/myservice.ca.cert.pem"),
      strictSSL: true
    }
    
    client = new CarbonClient(uri, defaultOptions);
    JSON/Plain-text Results

    All results are in JSON by default. For plain text, set options.json to false:

     // Plain text
     client.getEndpoint("hello").get({json: false}, function(e, response) {
       console.log("Response from /hello: " + response.body)
     })
    keepAlive

    keepAlive can be set through the forever option

    client = new CarbonClient(uri, {forever: true});
    timeout

    timeout can be set through the timeout option. Its an integer representing timeout in milliseconds. This applies to both connection and read timeouts.

    client = new CarbonClient(uri, {timeout: true});

    Class reference

    Keywords

    none

    Install

    npm i @carbon-io/carbon-client-node

    DownloadsWeekly Downloads

    10

    Version

    0.7.1

    License

    MIT

    Last publish

    Collaborators

    • nir-jacobson
    • matt.hardock
    • gregbanks
    • willshulman
    • robert.mlab
    • abdulito
    • tfogo