Giter Club home page Giter Club logo

node-heroku-client's Introduction

Node Heroku Client

Build Status Code Climate

A wrapper around the v3 Heroku API.

Install

$ npm install heroku-client --save

Usage

To begin, require the Heroku module and create a client, passing in an API token:

const Heroku = require('heroku-client')
const heroku = new Heroku({ token: process.env.HEROKU_API_TOKEN })

heroku-client has get, post, patch, and delete functions which can make requests with the specified HTTP method to any endpoint:

// GET requests
heroku.get('/apps').then(apps => {
  // do something with apps
})

// POST requests
heroku.post('/apps').then(app => {})

// POST requests with body
heroku.post('/apps', {body: {name: 'my-new-app'}}).then(app => {})

// PATCH requests with body
heroku.patch('/apps/my-app', {body: {name: 'my-renamed-app'}}).then(app => {})

// DELETE requests
heroku.delete('/apps/my-old-app').then(app => {})

There is also an even more generic request function that can accept many more options:

heroku.request({
  method: 'GET',
  path: '/apps',
  headers: {
    'Foo': 'Bar'
  },
  parseJSON: false
}).then(response => {})

Generators

It's easy to get heroku-client working with generators. In this example, I'll use the co library to wrap a function that will get the list of all of my apps, and then get the dynos for each of those apps:

const co     = require('co')
const heroku = require('heroku-client')
const hk     = heroku.createClient({ token: process.env.HEROKU_API_KEY })

let main = function * () {
  let apps  = yield hk.get('/apps')
  let dynos = yield apps.map(getDynos)

  console.log(dynos)

  function getDynos(app) {
    return hk.get(`/apps/${app.name}/dynos`)
  }
}

co(main)()

Hooray, no callbacks or promises in sight!

HTTP Proxies

If you'd like to make requests through an HTTP proxy, set the HEROKU_HTTP_PROXY_HOST environment variable with your proxy host, and HEROKU_HTTP_PROXY_PORT with the desired port (defaults to 8080). heroku-client will then make requests through this proxy instead of directly to api.heroku.com.

Caching

heroku-client can optionally perform caching of API requests.

heroku-client will cache any response from the Heroku API that comes with an ETag header, and each response is cached individually (i.e. even though the client might make multiple calls for a user's apps and then aggregate them into a single JSON array, each required API call is individually cached). For each API request it performs, heroku-client sends an If-None-Match header if there is a cached response for the API request. If API returns a 304 response code, heroku-client returns the cached response. Otherwise, it writes the new API response to the cache and returns that.

To tell heroku-client to perform caching, add a config object to the options with store and encryptor objects. These can be instances of memjs and simple-encryptor, respectively.

var Heroku    = require('heroku-client');
var memjs     = require('memjs').Client.create();
var encryptor = require('simple-encryptor')(SECRET_CACHE_KEY);
var hk        = new Heroku({
  cache: { store: memjs, encryptor: encryptor }
});

Custom caching

Alternatively you can specify a custom cache implementation. Your custom implementation must define get(key, cb(err, value)) and set(key, value) functions.

Here's a sample implementation that uses Redis to cache API responses for 5-minutes each:

var redis        = require('redis');
var client       = redis.createClient();
var cacheTtlSecs = 5 * 60; // 5 minutes

var redisStore = {
  get: function(key, cb) {
    // Namespace the keys:
    var redisKey = 'heroku:api:' + key;
    client.GET(redisKey, cb);
  },

  set: function(key, value) {
    // Namespace the keys:
    var redisKey = 'heroku:api:' + key;
    client.SETEX(redisKey, cacheTtlSecs, value, function(err) {
      // ignore errors on set
    });
  }
};

var encryptor = require('simple-encryptor')(SECRET_CACHE_KEY);
var Heroku    = require('heroku-client');
var hk        = new Heroku({
  cache: {store: redisStore, encryptor: encryptor}
});

Contributing

Inspect your changes, and bump the version number accordingly when cutting a release.

Running tests

heroku-client uses ava for tests:

$ npm test

node-heroku-client's People

Contributors

appleton avatar bjeanes avatar bobzoller avatar camelmasa avatar chadian avatar dependabot[bot] avatar elbandito avatar jackca avatar jacobian avatar jclem avatar jdx avatar jheikes515 avatar joshwlewis avatar mimen avatar mrmicahcooper avatar msakrejda avatar nidin avatar owenthereal avatar rasphilco avatar raulb avatar rwz avatar sehrope avatar svc-scm avatar taytay avatar zwhitfield3 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  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  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  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  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  avatar  avatar  avatar  avatar  avatar

node-heroku-client's Issues

bump form 3.0.4 to 3.0.5 was actually a breaking change.

This commit here 78bc3d3 introduced the rest operator (...) which was introduced in node 6. This means that any node code running on node 4 does not work with [email protected].

It would have been nice if semver practices were followed here. Releasing a v4.0.0 would have prevented some legacy code that I have to maintain from breaking.

Along the same notes, in the package.json, it currently said the engines node is ">=4.0.0", but that is not true anymore with the rest operator. That should be updated as well.

How to upload a slug.tgz?

Hello,

I am trying to upload the slug file by following this tutorial (https://devcenter.heroku.com/articles/platform-api-deploying-slugs):

let buf = require("fs").readFileSync(__dirname + "/slug.tgz");
let app = await heroku.post("/apps" , buf)

the results are :

{ acm: false,
  archived_at: null,
  buildpack_provided_description: null,
  build_stack:
   { id: '69bee368-352b-4bd0-9b7c-819d860a2588',
     name: 'heroku-18' },
  created_at: '2019-10-29T02:04:28Z',
  id: 'f6d4d110-dbe8-42e7-aef8-6b5416ed8231',
  git_url: 'https://git.heroku.com/calm-ocean-84625.git',
  maintenance: false,
  name: 'calm-ocean-84625',
  owner:
   { email: '[email protected]',
     id: '63bb3b9a-6349-44e4-8cb4-ba54d6ee7b34' },
  region: { id: '59accabd-516d-4f0e-83e6-6e3757701145', name: 'us' },
  organization: null,
  team: null,
  space: null,
  internal_routing: null,
  released_at: '2019-10-29T02:04:28Z',
  repo_size: null,
  slug_size: null,
  stack:
   { id: '69bee368-352b-4bd0-9b7c-819d860a2588',
     name: 'heroku-18' },
  updated_at: '2019-10-29T02:04:28Z',
  web_url: 'https://calm-ocean-84625.herokuapp.com/' }

then i try to release the app:

heroku.post("/apps/" + app.name + "/releases", { slug: app.id })
 .then(app => { }) .catch(console.log);

and i am getting this error:

{ Error: Expected response to be successful, got 404
    at Request.handleFailure (@heroku\node_modules\heroku-client\lib\request.js:254:11)
    at concat.then (@heroku\node_modules\heroku-client\lib\request.js:148:16)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  statusCode: 404,
  body:
   { resource: 'slug',
     id: 'not_found',
     message: 'Couldn\'t find that slug.' } }

what is wrong with my code? is there an example how to upload the slug file with this module?

Thanks

How do I stop a dyno?

Hey,

Any idea how do I stop a running dyno, i.e. a dyno I created with heroku.apps({app_id_or_name}).dynos().create({attributes}, {callback});?

I don't seem to be able to find a #delete() method in the dyno.md docs.

The Platform API reference doesn't mention a DELETE method either.

Cheers,

How to use generic POST?

I have tried this but get a 400

heroku.request({
    method: 'POST',
    path: '/apps/' + appName + '/releases/',
    body: { 'slug': slugId },
    headers: {
        'Accept' : 'application/vnd.heroku+json; version=3',
        'Content-Type' : 'application/json'
    }
}, function (err, responseBody) {
    assert.ifError(err, "Could not copy slug " + slugId + " to app " + appName);
    console.log("Copied slug " + slugId + " to app " + appName);
});

Can you provide me the correct form?

Thanks

Ray

Middleware/caching/warning should be better

Expanding on #64 and #65 for breaking 3.x changes I would like to see, I think we can potentially reduce the amount of ways there are to configure this module while also making it more extensible.

Our "middleware" (which I added) is not really middleware, it's kind of more of a callback on each request. This is useful for detecting X-Heroku-Warning headers, but it might be able to be done in a better way. Potentially there could be an optional warn option that could be passed which would be a function taking in the warning string.

Alternatively, or maybe additionally, if the middleware was a real middleware that could allow users to both alter and cancel the request as well as modifying and looking at the response, we could perform the caching logic with the same code. This would make it more obvious how to extend the module and clean up the code a ton.

If we did this along with my other proposed changes, this module could probably be reduced to a single file only a few hundred lines long.

Unable to set Range header

I am unable to set the Range header using this client; I would like to order by desc and set the limit to 1 but I am unable to do so using this library.

Dude token

Hi guys, I have a dude

How I can transform the command heroku auth:token using the package? thanxs a lot

Deleting dynos is resulting in issues.

Error:

undefined:1
<html>
^
SyntaxError: Unexpected token <
    at Object.parse (native)
    at Request.handleFailure (/Users/yazad/Documents/app_name/node_modules/heroku-client/lib/request.js:229:19)
    at Request.bound [as handleFailure] (/Users/yazad/Documents/app_name/node_modules/heroku-client/node_modules/lodash/dist/lodash.js:718:21)
    at IncomingMessage.<anonymous> (/Users/yazad/Documents/app_name/node_modules/heroku-client/lib/request.js:129:15)
    at IncomingMessage.EventEmitter.emit (events.js:117:20)
    at _stream_readable.js:920:16
    at process._tickCallback (node.js:415:13)

Because:

<html>
  <head><title>411 Length Required</title></head>
  <body bgcolor="white">
    <center><h1>411 Length Required</h1></center>
    <hr><center>nginx/1.2.8</center>
  </body>
</html>

Code:

function restart(callback) {
  application.dynos().list(function(err, result) {
    async.filter(result, only_up, function(results) {
      async.each(result, restart_dyno, function(err, res) {
        console.log("DONE");
        callback();
      });
    });
  });
  function only_up(dyno, cb) {
    cb(dyno.state === 'up');
  };
  function restart_dyno(dyno, cb) {
    application.dynos(dyno.id).delete(function(err, res){
      console.log( err, res );
      cb(err);
    });
  };
};

Human error

I have probably missed something...

If I do this:

var assert = require('assert');

var Heroku = require('heroku-client'),
    heroku = new Heroku({ token: process.env.HEROKU_API_TOKEN });

exports.production = function(req, res){
    var app = heroku.apps('auth-test');
    app.info(function (err, app) {
        assert.ifError(err);
        console.log(app)
    });
};

and get this:

2013-12-11T23:21:00.901345+00:00 app[web.1]: assert.ifError = function(err) { if (err) {throw err;}};
2013-12-11T23:21:00.905512+00:00 app[web.1]: ^
2013-12-11T23:21:00.905795+00:00 app[web.1]: Error: Expected response to be successful, got 401
2013-12-11T23:21:00.905795+00:00 app[web.1]: at Request.handleFailure (/app/node_modules/heroku-client/lib/request.js:188:9)

Any ideas?

Error 503 on deploy from Travis

Not sure if this is an error with node-heroku-client or with the upstream service, but status.heroku.com indicates no issues.

I'm getting this error on deploy from Travis:

/home/travis/.rvm/gems/ruby-1.9.3-p551/gems/excon-0.55.0/lib/excon/middlewares/expects.rb:11:in `response_call': Expected([200, 201]) <=> Actual(503 Service Unavailable) (Heroku::API::Errors::ErrorWithResponse)
body: "{\"id\":\"unavailable\",\"message\":\"Could not complete the action. Please try again later.\"}"
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/excon-0.55.0/lib/excon/middlewares/response_parser.rb:9:in `response_call'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/excon-0.55.0/lib/excon/connection.rb:388:in `response'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/excon-0.55.0/lib/excon/connection.rb:252:in `request'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/heroku-api-0.4.2/lib/heroku/api.rb:84:in `request'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/provider/heroku/api.rb:95:in `post'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/provider/heroku/api.rb:33:in `trigger_build'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/provider/heroku/api.rb:13:in `push_app'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/provider.rb:146:in `block in deploy'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/cli.rb:41:in `fold'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/provider.rb:146:in `deploy'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/provider/heroku/generic.rb:57:in `deploy'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/cli.rb:32:in `run'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/lib/dpl/cli.rb:7:in `run'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/gems/dpl-1.8.31/bin/dpl:5:in `<top (required)>'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/bin/dpl:23:in `load'
  from /home/travis/.rvm/gems/ruby-1.9.3-p551/bin/dpl:23:in `<main>'

Here is my deploy config on travis (keys scrubbed):

deploy:
  provider: heroku
  run: npm run migrations
  api_key:
    secure: <SCRUBBED>
  skip_cleanup: true
  buildpack: nodejs
  app:
    develop: <SCRUBBED>
    master: <SCRUBBED>

Post request with body

hey suppose I want to do a post request with body so I specify the name . Suppose I want to have the deployment method as github . how could iset the the repository name and deployment method

Exposing full API response in error messages

Hey @jdxcode and @jclem ๐Ÿ‘‹

I'm using this client on a project at GitHub. So far it's been a breeze. Thanks for writing this nice module. ๐Ÿ“ฆ

I have noticed that sometimes the error handling is missing information. When I get a 409 or 422 back, the error message doesn't tell me much:

heroku.post('/app-setups', body).catch(err => {
  // console.error(err)
  // Expected response to be successful, got 409
})

I've gotten 409 and 422, both of which can take on different meanings depending on the context and the endpoint being used, so the status code has generally not been enough information to make the underlying problem evident.

Digging into the source, I see that a body property is attached to error object:

handleFailure (res, buffer) {
var message = 'Expected response to be successful, got ' + res.statusCode
var err
err = new Error(message)
err.statusCode = res.statusCode
try {
err.body = this.parseBody(buffer)
} catch (e) {
err.body = buffer
}
this.reject(err)
}

As far as I can tell, this body property is both undocumented and non-standard. Looking at the API for JavaScript's Error class, they have both a name and message property that can be used. Maybe we could use the combination of these two properties to have both succinct (name) and verbose (message) strings in the error object.

Am I on the right track here? If so, would you be open to a pull request that either documents this behavior, or changes the behavior to make error messages more verbose (and useful) by default?

Buildpack Installation API failure

This code return 500, same thing happens with buildpackInstallations().update even though I'm pretty sure buildpack still being updated.

heroku.apps(<app-id-or-name>).buildpackInstallations().list(function(err, response) {
  console.log("log", err, response);
});

I tried with heroku-cli, response still fine 200 with buildpack information. Please check screenshot below

image

image

Promises

Hi Jonathon,

A quick question ... if I try to use promises I don't get the failure mode I was expecting... the error message comes out from your code but I don't see it. Moreover this means that the node process exits normally and I would prefer it to exit with a non-zero status code.

[ If I use standard node callbacks all is good but gets ugly quick as I add more code ]

Here is my sample code using the promise style

function checkAcount() {
    console.log("Validating user access");
    heroku.get('/account').then(function (user) {
        console.log("We are deploying with account: " + JSON.stringify(user));
    }).catch(function (error) {
        throw Error("Account check FAIL: " + error);
    });
}

This also does not work if I use fail instead of catch (as mentioned by the Q library author)

What is the correct way to obtain exceptions?

Thanks in advance for your support

Ray

[HOW TO] Add an addon to my app

I want to add an addon - heroku-postgresql to my app. Is it possible to do the same using heroku-client? Please let me know asap. :)

pipelineCouplings always returns 503 and is incorrectly documented

This code, where pipelineName=pipelinename here, but is a real pipeline name in actuality:

heroku.pipelines(pipelineName).pipelineCouplings().list().then(function (info) {
    debug('stage info', info);

always returns a 503

--> GET /pipelines/pipelinename/pipeline-couplings
    accept=application/vnd.heroku+json; version=3
    content-type=application/json
    user-agent=node-heroku-client/2.4.2
    range=id ]..; max=1000
    host=api.heroku.com
    authorization=REDACTED
{ status: 503,
  content_length: '87',
  request_id: '942b02c5-357e-496f-a8ed-057b05bb3a58' }
<-- 503 undefined
    cache-control=private, no-cache
    content-type=application/json
    date=Tue, 22 Mar 2016 11:22:13 GMT
    ratelimit-multiplier=3
    ratelimit-remaining=4497
    request-id=942b02c5-357e-496f-a8ed-057b05bb3a58
    server=nginx/1.8.1
    vary=Accept-Encoding
    x-content-type-options=nosniff
    x-runtime=0.854349235
    content-length=87
    connection=keep-alive
<-- {"id":"unavailable","message":"Could not complete the action. Please try again later."}
deploy:setup failed with error:  { [Error: Expected response to be successful, got 503]
  statusCode: 503,
  body: 
   { id: 'unavailable',
     message: 'Could not complete the action. Please try again later.' } } Error: Expected response to be successful, got 503

According to Heroku Support, you cannot use the pipeline name to make the GET /pipelines/pipelinename/pipeline-couplings call, but must use the pipeline ID instead. So both the documentation and the code need to be updated to correctly work with pipeline couplings. Similar to how you disambiguate app names, I would hope that you would accept a pipeline name and behind the scenes look up the pipeline id and then make a properly formed request.

How to use with a proxy?

How can I make requests using a http proxy?

I read the request.js but could not see that possibility

Thanks

Ray

Typescript types?

Could we add TS types to this repo for the api options? After a first looksie for @types/heroku-client and @types/node-heroku-client I didn't see anything.

Happy to add this to another repo if this is not the right spot, thanks!

Unable to use custom range

I'm wanting to select the last 10 recent releases. I'm trying to provide a custom range header like this:

heroku = new Heroku({ 
    token: process.env.HEROKU_API_TOKEN, 
    headers: { Range: "version ]..; order=desc,max=10;"}
});
heroku.apps(app).releases().list(function(err, releases) { ... });

The problem is that this api call still returns the Next-Range and
this is will always make additional api requests to get the rest of the list. This can be time consuming as I potentially have several thousand records but more importantly it causes an infinite loop because it never fetches the next range since I have overriden the Range header.

Ideally we should be able to override this behavior. Perhaps there already is and I'm just missing it? What's the proper way of handling paging?

Requiring modules in functions causes them unable to be used with mocked filesystem

Hello again!

So after updating heroku-cli-util to v6 (which bumped this module req to v3beta) a couple of tests started failing (see Travis build) because internal modules couldn't be found.

Turns out the source is lines like this where modules are required in functions. I extensively mock the filesystem (using mock-fs). Since the requires happen in functions, there's no point where we can make http requests when the fs mock is active.

Per this fairly well-starred node best practices guide, developers should refrain from requiring modules in functions. While it does speed up initial load time (because it only runs synchronous code if and when the function is actually used), it has unexpected consequences down the line.

Looking at the code, the best solution seems to be requiring everything at the top of the file, like most node projects. Is that something you'd be open to?

Heroku Org Patch Request

Whenever running a PATCH request to Lock an application; it doesn't lock. We get no error message it just outputs the name of the application it has "apparently" locked.

This is the command we are running to lock the application:

console.log("About to Patch Application to lock: ");
herokuClient.patch('organizations/apps/lusa-web-test-prototype', { locked: true }, (err, app) => {
console.log(err);
console.log(app);
}

This just returns the app name; no error message.

The output looks like:

12:22:02 PM web.1 | Patching Heroku Instance: lusa-web-test-prototype

Whenever we run a CURL command it locks perfectly. So it's nothing wrong with the API Key?

Is this an issue your side?

Consider adding Changelog.md

Hi,

my short term question is what has changed (which may break my code) between 2.4.3 and 3.0.2 versions.

I tried this, but it's not particularly clear to someone, like me, who is just a user of the lib.

update: I noticed that your api wrapper now returns promises; is there anything else, which is less immediately observable?.

On the long term, are you considering adding a Changelog.md file, or could you point me to it, if it does already exists?

Thanks.

Module load time is very slow

Because we heavily depend on this plugin for virtually all Heroku CLI plugins, the module load time is very important. Right now in the new CLI this module takes about 100ms to load because of this massive file and the inflection that it does. This is over half of the entire time the CLI takes to load.

This wasn't really a problem with the Ruby CLI wrapping the new CLI as it took a (relatively) long time to start, over a second in many cases. The 100ms cost of this was comparatively low. Now that the load time is reduced to less than 200ms, this 100ms is a big cost to the CLI performance.

The proxy objects this generates appear useful, and I used them when first building the CLI code but quickly found them to be less useful than they appear and found myself switching between them and simple heroku.get/heroku.request calls. Ultimately I found it was just easier, and even less code to use the manual calls everywhere.

Because I've been discouraging the use of them to users of this client as well as the performance issues we're now experiencing, I plan to remove proxy objects in a new 3.x release of the package.

We could improve on the method of calling this module and provide more direction into an opinionated "best" way to use the module. After using this for almost 2 years heavily, I think I have a good idea of what that would look like outlined in #65.

In addition, I think all the dependencies can go away. Currently the production dependencies are:

  • inflection, path-proxy: Used for the proxy object.
  • q: node 0.12 is the newest version of node that does not support native promises. Because it is now in maintenance, we can safely drop node <4.x support in the new major version and stick to native promises.
  • tunnel-agent: I need to investigate a bit further, but I think we can just make the agent configurable and easily allow the calling package to provide tunnel-agent for proxy setups. The method got uses seems ideal here.

This package is however, very stable, and I see no problem with providing updates via a 2.x branch. We will still provide updates to the documentation and updating the API for users that want to continue using it.

Cannot send build with basic auth

Hello,

I bumped into what I believe to be a bug in the Heroku API. Whenever I try to create a build using the basic user+pass authentication, I get a generic 500 application_error. If instead of the basic auth I use the token, everything works fine.

How to reproduce

This works:

const Heroku    = require("heroku-client");
const heroku    = new Heroku({ token: ... });

heroku.post(`/apps/.../builds`, {
    body: {
        source_blob: {
            url: tarball_url
        }
    }
})

This doesn't work:

const Heroku    = require("heroku-client");
const heroku    = new Heroku({ auth: `...:...` });

heroku.post(`/apps/.../builds`, {
    body: {
        source_blob: {
            url: tarball_url
        }
    }
})

All the other endpoints that I've tried so far (listing the apps, creating an app and so on) have no problem whatsoever with the basic authentication, only this one.

Options for get/post/patch/delete helpers

Expanding on #64 for items I want to see in a new major version:

Often when using this module, it can be nice to be able to use the helper functions, but they break down when more configuration is needed. For example, if you want to send a PATCH request to /apps/:app_id to rename an app, you can do the following:

heroku.patch(`/apps/${app}`, {name: 'newname'})

This breaks down if you need to do something such as adding headers to the request though, and you need to use heroku.request instead:

heroku.request({
  method: 'PATCH',
  path: `/apps/${app}`,
  body: {name: 'newname'},
  headers: {foo: 'bar'}
})

This is a pain point. It requires rewriting a lot of code, and the CLI is cluttered with many uses of this. Also, for some reason, heroku.delete doesn't take a body. Because of this, I never use the body helper functions and pretty much only use heroku.get().

I think instead of having the second argument to the helpers be a body, we can just change it to request options:

heroku.patch(`/apps/${app}`, {
  body: {name: 'newname'},
  headers: {foo: 'bar'}
})

This will make the helpers ultimately flexible, and matches the code with using heroku.request. Editing code to add/remove headers, change http method, or anything else requires only small changes to the call, not total rewrites like we have today. This, combined with removing proxy objects will provide an opinionated, yet flexible direction for users.

Better API

Rather than deleting a collaborator like this:

heroku.collaborators.delete('my-app', '[email protected]');

The following would be an easier to understand API:

heroku.apps('my-app').collaborators('[email protected]').delete();

problem obtaining organizations (404)

I have this code:

function getAppsForOrganization(organization) {
   var getUrl = '/organizations/' + organization + '/apps';
    return heroku.get(getUrl).then(function (apps) {
        return apps;
    }).catch(function (error) {
        console.error('DEBUG in getAppsForOrganization(), failed call to heroku: ' + error);
    });
}

I currently get a 404 from the client whilst the same URL works fine if I do the same call from the command line

DEBUG in getAppsForOrganisation(), failed call to heroku: Error: Expected response to be successful, got 404

$ curl -n -X GET https://api.heroku.com/organizations/tme-web-preview/apps -H "Accept: application/vnd.heroku+json; version=3"

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.