Giter Club home page Giter Club logo

node-bandwidth's Introduction

node-bandwidth

Deprecation Notice

This project is deprecated. Please go to https://github.com/bandwidth/node-voice or https://github.com/bandwidth/node-messaging for using Bandwidth's voice and messaging APIs.

npm version Build Status dependencies Known Vulnerabilities

A Node.js client library for Bandwidth's Communications Platform

API Documentation

The API documentation is located at dev.bandwidth.com/ap-docs/

The Full API Reference is available either as an interactive site or as a single Markdown file:

Installing the SDK

node-bandwidth is available on NPM:

npm install --save node-bandwidth

Supported Versions

node-bandwidth should work on all versions of node newer than 6.0.0. However, due to the rapid development in the Node and npm environment, we can only provide support on LTS versions of Node

Version Support Level
< 6 Unsupported
6-12 Supported
> 12 N/A

Release Notes

Version Notes
3.0.0 Dropped support for node versions less than 6
3.0.2 Updated the URL used for Bandwidth's V2 Messaging

Client initialization

All interaction with the API is done through a client Object. The client constructor takes an Object containing configuration options. The following options are supported:

Field name Description Default value Required
userId Your Bandwidth user ID undefined Yes
apiToken Your API token undefined Yes
apiSecret Your API secret undefined Yes
baseUrl The Bandwidth API URL https://api.catapult.inetwork.com No

To initialize the client object, provide your API credentials which can be found on your account page in the portal.

var Bandwidth = require("node-bandwidth");

var client = new Bandwidth({
	userId    : "YOUR_USER_ID", // <-- note, this is not the same as the username you used to login to the portal
	apiToken  : "YOUR_API_TOKEN",
	apiSecret : "YOUR_API_SECRET"
});

Your client object is now ready to use the API.

Callbacks or Promises

All functions of the client object take an optional Node.js style (err, result) callback, and also return a Promise. That way if you want to use Promises in your application, you don't have to wrap the SDK with a Promise library. You can simply do things like this:

Promise style

client.Message.send({
	from : "+12345678901", // This must be a Catapult number on your account
	to   : "+12345678902",
	text : "Hello world."
})
.then(function(message) {
	console.log("Message sent with ID " + message.id);
})
.catch(function(err) {
	console.log(err.message);
});

If you're not into that kind of thing you can also do things the "old fashioned" callback way:

Callback style

client.Message.send({
	from : "+12345678901", // This must be a Catapult number on your account
	to   : "+12345678902",
	text : "Hello world."
}, function(err, message) {
	if (err) {
		console.log(err);
		return;
	}
	console.log("Message sent with ID " + message.id);
});

Using Messaging V2 API

Both callback and promise styles are supported

// First you should create and application on Bandwidth Dashboard
var dashboardAuth = {
	accountId    : "accountId",
	userName     : "userName",
	password     : "password",
	subaccountId : "subaccountId"
};

client.v2.Message.createMessagingApplication(dashboardAuth, {
    name: "My Messaging App",
    callbackUrl: "http://my-callback",
    locationName: "My Location",
    smsOptions: {
        enabled: true,
        tollFreeEnabled: true
    },
    mmsOptions: {
        enabled: true
    }
}).then(function (application) {
	// application.applicationId contains id of created dashboard application
	// application.locationId contains id of location

	// Now you should reserve 1 ore more numbers on  Bandwidth Dashboard
	return client.v2.Message.searchAndOrderNumbers(dashboardAuth, application, new client.AreaCodeSearchAndOrderNumbersQuery({areaCode: "910", quantity: 1}))
		.then(function (numbers) {
			// Now you can send messages using these numbers
			return client.v2.Message.send({from: numbers[0], to: ["+12345678901", "+12345678902"], text: "Hello", applicationId: application.applicationId});
		});
});

Providing feedback

For current discussions on 2.0 please see the 2.0 issues section on GitHub. To start a new topic on 2.0, please open an issue and use the 2.0 tag. Your feedback is greatly appreciated!

node-bandwidth's People

Contributors

a-type avatar amiller-gh avatar aubron avatar avbel avatar bioform avatar edhintz avatar ffranco-daitan avatar fuchsnj avatar guaycuru avatar jchavez443 avatar jhorwitz828 avatar jmulford-bw avatar marcosc90 avatar nguyer avatar rjmill avatar rrao24 avatar sbertrand101 avatar scottbarstow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-bandwidth's Issues

Batch Messages

Need to add ability to send array of messages.

Dox

and parsing the response, since it returns an array of message results now, instead of just a blank 201

Fix NPM Install Warnings

Dashboard Auth - Do not use main password, rather use a token

Using dashboardAuth in your API like so:

var dashboardAuth = {
accountId : "accountId",
userName : "userName",
password : "password",
subaccountId : "subaccountId"
};

means that we have to store the actual password (same that controls billing, etc.) in the source code/environment variables/etc. I consider that a terrible practice. Could we have dashbordAuth object using just some tokens instead?

remove need to pass client

As a developer when I instantiate a catapult Client object I expect all methods to be attached to this object and not a separate Catapult object.

Instead of:

var client = new Catapult.Client(...);
Catapult.Message.create(client, ...);

I want:

var catapult = new Catapult.Client(...);
catapult.Message.create(...);

Number update and delete functions require a reference to the PhoneNumber object

In order to update or delete a phone number, we currently need to have a reference to the PhoneNumber object, because update and delete are prototype functions of PhoneNumber. This means that at some point we need to search or query for the number that we want to update (or delete) which requires another API call. This is a case of the SDK actually making things harder than using the API directly.

We should be able to call an update or delete function and simply pass in the number to updated or deleted. This capability is currently missing.

New Release

Hello @Aubron!

Sorry to be that person on GitHub (nobody likes that person...) but wanted to bump getting a release cut with #156 included so I can get my product off of a commit-pegged version and to a proper semver release.

Is there a better channel to join for process requests like this so I can help keep your issues tab clean?

Recording FileFormat for create/edit call missing

POST https://api.catapult.inetwork.com/v1/users/u-/calls/c-asdf
{
  "recordingEnabled": "true",
  "recordingFileFormat": "WAV"
}

Image

POST https://api.catapult.inetwork.com/v1/users/u-/calls
{
  "from": "+987",
  "to": "+1789",
  "recordingFileFormat": "MP3",
  "sipHeaders": {}
}

Image

promise support

If a callback is not passed to any method then a promise should be returned. I'd like to suggest using Bluebird. Here is an example of "promisifying" the existing library in one of my applications;

var Catapult = require("node-bandwidth");
var Bluebird = require("bluebird");

Bluebird.promisifyAll(Catapult.Message);

var client = new Catapult.Client({
    apiToken  : process.env.BANDWIDTH_API_TOKEN,
    apiSecret : process.env.BANDWIDTH_API_SECRET,
    userId    : process.env.BANDWIDTH_USER_ID
})

Catapult.Message.createAsync(client, {
    to   : "+19199463223",
    from : "+15713170274",
    text : "this is a test"
})
.then(function (message) {
    console.log("sent message: " + JSON.stringify(message));
})
.catch(function (err) {
    console.log("failed to send message: " + message);
});

Response errors don't go up the stream

Let's say im sending an SMS message with a wrong field

{'from':'..','to':'...','message':{'text':'...','notgood':'....'}}

The error I get after using client.Message.sendGroup(...).catch(function(err){}); doesnt reflect the actual error and only says: ResponseError

This is a serious issue as it prevents from debugging the code properly

it should be fixed in the lib/client.js makeRequest function probably

Filter messages by deliveryState 'not-delivered' fails with error

client.Message.list({deliveryState:'not-delivered'}, function(err, result) { console.log(err); });

results in the following error in the console:

{ [The 'deliveryState' parameter is the wrong type or does not follow the required format.]
  name: '',
  message: 'The \'deliveryState\' parameter is the wrong type or does not follow the required format.',
  statusCode: 400 }

simplify client options building

The code for building client options in the constructor of Client is very dense at the moment. I think it would be greatly simplified if we used something like lodash#defaults for setting defaults. It might be simpler if options are always read from the options object too.

Lodash will be very useful in other areas of this project as well.

vNext API suggestions

Feedback, in order, while reviewing the v-next branch:

Externals (usage)

Supported language versions

Sorry to be blunt, but asking developers to transpile their code or use only the latest version of Node is unreasonable for a mainline SDK. I don't know of any other (popular) library which does this. The library should be responsible for transpiling its source using Babel or TS before shipping. Libraries can also provide alternate main files which target specific module systems.

Async iterators

I consider myself fairly seasoned in JS development, but I've never seen async iterator syntax before. Looks similar to generators (and I saw a generator in the code under the hood). I'm confused as to why there are two await statements. The proposal uses the for await (... of syntax and does not include multiple await statements. I'm guessing this is because the method itself which returns the iterator is asynchronous. This indicates to me that this iteration usage was kind of shoehorned into a pattern which wasn't designed to support it.

Really, I think this syntax is too new for expected adoption. I question the removal of fetchNextPage or similar helpers to assist developers who do not want to use iterators, which I imagine will be the majority. fetchNextPage is very easy to understand and would be useful as a promise-based tool within this library. As a developer I'd prefer to have the simplest tools immediately available and be able to extend the experience using advanced tools if I want to. I think it would make more sense to have fetchNextPage be the default packaged solution for iterating through pages, and then provide a helper from the library like createItemIterator() which would allow me to use an async iterator instead if I choose to construct one. A Node 8 user should be able to just ignore async iterators altogether and get on with developing the way they're used to.

const firstPage = await api.calls.list();
// user can now access first page items as usual.
firstPage.forEach(message => console.log(message.text));
// user can also easily iterate pages with familiar concepts
const secondPage = await firstPage.fetchNextPage();
// or, user can iterate through items without worrying about pagination
const itemIterator = createItemIterator(firstPage);
for await (const message of itemIterator) {
  console.log(message.text);
}
// OR, the user can iterate through pages
const pageIterator = createPageIterator(firstPage);
for await (const page of pageIterator) {
  page.forEach(message => console.log(message.text);
}

This also solves the design problem where the .list() method returns entirely different kinds of objects depending on whether you passed in a { page } parameter or not. Methods should return the same type no matter what you pass in.

Client instantiation

Top-level client creation should be a class instantiation, not a function call. Under the hood a Proxy class is being created around a BandwidthApi class already. Obscuring this behind a function call is odd and only seems to be necessary because of the Proxy usage. See more thoughts on Proxy below.

Naming conventions

Top-level properties for domains of api calls are just groupings, and should not be capitalized. Capitalized names are for class references only in standard JS formatting.

api.Calls.get --> api.calls.get

Leaking implementation concerns

The library should not expose any details about the underlying HTTP tooling it uses to make requests. If you want to support cancellation of requests, it should be through a generic means, not by requiring the user to reference the axios library.

Documentation

Language / typos / mistakes in Readme would need to be cleaned up as well, but that's pretty standard stuff.

Internals (code structure)

Proxies

Proxy usage seems confusing and unnecessary. It seems simpler and more maintainable just to assign properties directly to the BandwidthApi class, either statically or dynamically. "ApiObject"s seem to be generated lazily at runtime based on access. I don't see the advantage of such a complicated access pattern besides negligible memory saving. I would expect instantiation to look more like this:

import apiData from './apiData';

class BandwidthApi {
  constructor(options = {}) {
    // the following create a nested map structure:
    // { Calls: { get: [Function bound to this], list: [Function bound to this]...
    const bindApiMethods = obj => Object.keys(obj).reduce((methods, key) => ({
      ...methods,
      [key]: this.createApiMethod(obj[key]).bind(this),
    }, {});
	const apiObjects = apiData.reduce((structured, obj) => ({
      ...structured,
      [obj.name]: bindApiMethods(obj),
    }, {});

    // now all bound API domain objects are accessible from this instance.
    Object.assign(this, apiObjects);
  }
}

Basically, the way you've used Proxy adds a lot of indirection and slight-of-hand to the way the code operates. This does not encourage outside contribution. Even though I understand what a Proxy is, I still have a hard time following the path a function call takes through the client object, how it's bound, etc.

Mutation

The code seems to use mutation of objects pretty liberally, which I think is dangerous in a loosely typed language like JS. If you pass an object to a method which may attach properties to it, you'd then have to check to see if those properties are defined every time you want to use them afterwards; quite a pain. On top of that, any asynchronous tasks which may have been referencing that object may see its data changed without warning at any time. Functional programming prefers immutable data.

allow creating a `Domain` object from a domain id

Right now you have to retrieve a list of ALL of the domains on your account, and filter that list to get the one you want. In a perfect world you should be able to create this object without any HTTP requests being sent.

Problem with Media.download

I'm having a problem downloading a JPEG via the client.Media.download() method. How do I get the binary file for a JPEG?

I see that the content is type String | Buffer | Readable. Do I have to encode/process this somehow to get the raw file? Any advice or example here would be greatly appreciated.

Improving efficiency and consistency of Message.create

Message.create has different behavior and return results depending on whether one message or a list of messages is passed to the function.

When you call Message.create with a list of messages the callback for success is an array of objects containing the id of the message if that message was successfully sent, otherwise it is the error for that given message. If the caller wants more details about a particular message that was sent, they call Message.get and pass in the id.

When you call Message.create with a single message it behaves differently.

Expected: An array of one object that contains the id of the message or the error if it failed. If I want more details about the message (which I generally do not need) I can call Message.get with the id.

Actual: Single object with details about the message sent. This makes processing the result more complex than it needs to be. If I always get an array even if it is an array of 1 for a single message I can process the results the same regardless of the number of messages sent. Moreover, Message.create when passed a single message internally calls Message.get with the id of the message (this does not happen if you pass a list of messages). This means the package makes an extra REST call back to the Bandwidth Application Server that I did not ask for and may not need. We send a large number of single messages that results in twice as many REST calls to the Bandwidth Application Server than necessary.

As a user of node-bandwidth, I'd like the same structure sent to the call back of Message.create so that processing the result is simpler.

As a user of node-bandwidth, I'd like Message.create to not call Message.get internally to avoid an unnecessary REST call to the Bandwidth Application Server. If I need the message details, I can call Message.get explicitly.

SDK functions crash when called without a callback

Right now, there are no checks to make sure a callback has been passed to an SDK function before attempting to call it. In a situation where someone wants to call a function in a "fire and forget" manner, and does not provide a callback function, this causes the application to crash.

We should check to make sure callbacks are set before attempting to call them.

Suggestion: Add parameter to Call.speakSentence to specify the voice

Call.speakSentence is a convenient way to have an automated voice speak into call. We have found that some sentences are easier to understand in specific voices. Call.speakSentence always speaks the sentence in Kate's voice. Would like to specify a different voice.

Call.playAudio is a work around. However, speakSentence is more discoverable and convenient.

Downloading mms image files

I'm using Media.download to download an image file from an mms, and I'm having trouble processing the response body content.

A typical response looks like this:

{
  contentType: 'image/jpeg;name=image000000-m-c5qhcr3dxokuvrqpraiqxli.jpg',
  content: '����\u0000\u0010JFIF\u0000\u0001\u0001...
}

I can't seem to successfully save this content to a file and open it as an image. Is there some type of encoding that needs to be performed on this response?


I've submitted a pull request to fix this issue #112

Media tests break on node v8.1.2

Steps to recreate

  • Clone fresh repo
  • Ensure you're on master branch
  • Ensure you're using v8.x of node. Changelog
  • npm install
  • npm test
  • Watch as media tests fail
  • Or run
$ mocha -R spec test/media-test.js
  Media API
    global methods
      1) should upload a media file (Buffer), Promise
      2) should upload a media file (Buffer) with content type, Promise
      3) should upload a media file (Buffer), callback
      4) should upload a media file (Buffer) with content type, callback
      5) should upload a media file (stream), Promise
      6) should upload a media file (stream) with content type, Promise
      7) should upload a media file (file), Promise
      8) should upload a media file (file) with content type, Promise
      9) should throw error if uploaded data is invalid
      10) should throw error if fs.stat failed
      ✓ should download a media file
      ✓ should list media files
      ✓ should remove a media file


  3 passing (68ms)
  10 failing

  1) Media API global methods should upload a media file (Buffer), Promise:
     Error: Nock: No match for request PUT https://api.catapult.inetwork.com/v1/users/fakeUserId/media/file1 1234567890
      at end (node_modules/nock/lib/request_overrider.js:259:17)
      at OverriddenClientRequest.RequestOverrider.req.end (node_modules/nock/lib/request_overrider.js:159:7)
      at Request.end (node_modules/request/request.js:1528:14)
      at Readable.onend (_stream_readable.js:584:10)
      at endReadableNT (_stream_readable.js:1045:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  2) Media API global methods should upload a media file (Buffer) with content type, Promise:
     Error: Nock: No match for request PUT https://api.catapult.inetwork.com/v1/users/fakeUserId/media/file2 1234567890
      at end (node_modules/nock/lib/request_overrider.js:259:17)
      at OverriddenClientRequest.RequestOverrider.req.end (node_modules/nock/lib/request_overrider.js:159:7)
      at Request.end (node_modules/request/request.js:1528:14)
      at Readable.onend (_stream_readable.js:584:10)
      at endReadableNT (_stream_readable.js:1045:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  3) Media API global methods should upload a media file (Buffer), callback:
     Error: Nock: No match for request PUT https://api.catapult.inetwork.com/v1/users/fakeUserId/media/file1 1234567890
      at end (node_modules/nock/lib/request_overrider.js:259:17)
      at OverriddenClientRequest.RequestOverrider.req.end (node_modules/nock/lib/request_overrider.js:159:7)
      at Request.end (node_modules/request/request.js:1528:14)
      at Readable.onend (_stream_readable.js:584:10)
      at endReadableNT (_stream_readable.js:1045:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  4) Media API global methods should upload a media file (Buffer) with content type, callback:
     Error: Nock: No match for request PUT https://api.catapult.inetwork.com/v1/users/fakeUserId/media/file2 1234567890
      at end (node_modules/nock/lib/request_overrider.js:259:17)
      at OverriddenClientRequest.RequestOverrider.req.end (node_modules/nock/lib/request_overrider.js:159:7)
      at Request.end (node_modules/request/request.js:1528:14)
      at Readable.onend (_stream_readable.js:584:10)
      at endReadableNT (_stream_readable.js:1045:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  5) Media API global methods should upload a media file (stream), Promise:
     Error: Nock: No match for request PUT https://api.catapult.inetwork.com/v1/users/fakeUserId/media/file1 1234567890
      at end (node_modules/nock/lib/request_overrider.js:259:17)
      at OverriddenClientRequest.RequestOverrider.req.end (node_modules/nock/lib/request_overrider.js:159:7)
      at Request.end (node_modules/request/request.js:1528:14)
      at Readable.onend (_stream_readable.js:584:10)
      at endReadableNT (_stream_readable.js:1045:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  6) Media API global methods should upload a media file (stream) with content type, Promise:
     Error: Nock: No match for request PUT https://api.catapult.inetwork.com/v1/users/fakeUserId/media/file2 1234567890
      at end (node_modules/nock/lib/request_overrider.js:259:17)
      at OverriddenClientRequest.RequestOverrider.req.end (node_modules/nock/lib/request_overrider.js:159:7)
      at Request.end (node_modules/request/request.js:1528:14)
      at Readable.onend (_stream_readable.js:584:10)
      at endReadableNT (_stream_readable.js:1045:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  7) Media API global methods should upload a media file (file), Promise:
     Error: Nock: No match for request PUT https://api.catapult.inetwork.com/v1/users/fakeUserId/media/file1 1234567890
      at end (node_modules/nock/lib/request_overrider.js:259:17)
      at OverriddenClientRequest.RequestOverrider.req.end (node_modules/nock/lib/request_overrider.js:159:7)
      at Request.end (node_modules/request/request.js:1528:14)
      at ReadStream.onend (_stream_readable.js:584:10)
      at endReadableNT (_stream_readable.js:1045:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  8) Media API global methods should upload a media file (file) with content type, Promise:
     Error: Nock: No match for request PUT https://api.catapult.inetwork.com/v1/users/fakeUserId/media/file2 1234567890
      at end (node_modules/nock/lib/request_overrider.js:259:17)
      at OverriddenClientRequest.RequestOverrider.req.end (node_modules/nock/lib/request_overrider.js:159:7)
      at Request.end (node_modules/request/request.js:1528:14)
      at ReadStream.onend (_stream_readable.js:584:10)
      at endReadableNT (_stream_readable.js:1045:12)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  9) Media API global methods should throw error if uploaded data is invalid:
     Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
      at test/media-test.js:111:5
      at tryCatcher (node_modules/bluebird/js/release/util.js:16:23)
      at Promise.errorAdapter [as _rejectionHandler0] (node_modules/bluebird/js/release/nodeify.js:35:34)
      at Promise._settlePromise (node_modules/bluebird/js/release/promise.js:566:21)
      at Promise._settlePromise0 (node_modules/bluebird/js/release/promise.js:614:10)
      at Promise._settlePromises (node_modules/bluebird/js/release/promise.js:689:18)
      at Async._drainQueue (node_modules/bluebird/js/release/async.js:133:16)
      at Async._drainQueues (node_modules/bluebird/js/release/async.js:143:10)
      at Immediate.Async.drainQueues (node_modules/bluebird/js/release/async.js:17:14)

  10) Media API global methods should throw error if fs.stat failed:
     Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
      at test/media-test.js:120:5
      at tryCatcher (node_modules/bluebird/js/release/util.js:16:23)
      at Promise.errorAdapter [as _rejectionHandler0] (node_modules/bluebird/js/release/nodeify.js:35:34)
      at Promise._settlePromise (node_modules/bluebird/js/release/promise.js:566:21)
      at Promise._settlePromise0 (node_modules/bluebird/js/release/promise.js:614:10)
      at Promise._settlePromises (node_modules/bluebird/js/release/promise.js:689:18)
      at Async._drainQueue (node_modules/bluebird/js/release/async.js:133:16)
      at Async._drainQueues (node_modules/bluebird/js/release/async.js:143:10)
      at Immediate.Async.drainQueues (node_modules/bluebird/js/release/async.js:17:14)

Passing in a client object to send SMS does not work

The README.md states that one should be able to create a client object and pass it into any of the methods to make API calls like this:

var client = new catapult.Client("userId", "apiToken", "apiSecret");
catapult.Message.create(client, {from: "+19195551212", to: "+191955512142", text: "Test"}, function(err, message){...});

This does not work. Only using the global client object, does sending SMS actually work.

Media download binary data issue

I am trying to upload media files to S3 to be able to access by our users. Unfortunately, after using the download function and uploading it to s3, the audio doesn't play.

I used hex editor and the binary version of the file using the node library download function is completely different, for some reason.

How do I fix this?

Suggestion: API to get content length and type for single media file

There are situations where you want to know the length and type of a single media file without downloading it and without searching through a list of tens of thousands of media records. For example, you have a mobile application and you want to show the user the size and type of the media file before they decide to download it and have it impact their data plan.

Media.list will show me content length, but not content type. Moreover, if you have a very large number of media files you have to download the entire list and find the one you are interested in.

I suggest a Media.getInfo passing in the filename or Media.list with a filename query parameter and the ability to return content-type and content-length.

Trouble with SDK Honoring Promises

It's not covered in the documentation, but when I receive a callback from Bandwidth (e.g. from an incoming call), how am I supposed to respond to that callback? I'm assuming that I should just make REST calls instead of responding with some kind of string (likeI would with Twilio), ##but I'm having all kinds of issues:

  1. Tried using SDK to can REST interface with callId to do something basic, like answer, then speak sentence, then hangup. It seems like the SDK was not honoring promises and instead just skipped over the subsequent .then() statements.

  2. Tried to create some BXML and send it back as a response. That didn't do anything.

  3. Gave up with all of that, and just decided to use the SDK to fire off an SMS when the callback is hit. This is having the same issue as #1 where it jut skips over the .then() statements. Below is my code and output... what am I doing wrong here?

`'use strict';

const Bandwidth = require('node-bandwidth');

exports.handle = function (event, context, callback) {

console.log('Received event: ', JSON.stringify(event, null, 2));
console.log('Received context: ', JSON.stringify(context, null, 2));

if(event.eventType === 'incomingcall') {
    let client = new Bandwidth({
        userId: 'u---------------------------',
        apiToken: 't--------------------------',
        apiSecret: '---------------------------'
    });

    console.log('Pre');
    client.Message.send({
        from: '+1----------',
        to: '+1----------',
        text: 'This is a test message'
    })
    .then(message => {
        console.log('sent a message: ' + message);
    })
    .catch(err => {
        console.log('error: ' + err.message);
    })
    .finally(() => {
        console.log('hit the finally block');
        return context.succeed();
    });

    console.log('how did I get here?');
}
else {
    console.log('Incoming connection was not an incoming call');
    return context.succeed();
}   

}`

Output:
... after the event and context objects are spit out on the console...
Pre
how did I get here?

... and no message was sent
... probably not an issue, but I can't find anywhere else to get support for the SDK...

Add JSHint and JSCS with Gulp or Grunt

Right now the project does not use any sort of build tool. In addition there is no enforcement of any sort of consistent style, or automatic linting. We should add Gulp or Grunt to our project so that we can establish some objective rules around "acceptable" code contributions.

Updated for V2

Any hopes of this node package being fully updated to support all the endpoints and capabilities of Bandwidth's V2 API? (phone number ordering, etc.)

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.