Repository navigation
storage: storage.createBucket('name', cb) #168
Description
Activity
This makes sense to me. Is there any reason we can't do this @silvolu?
https://developers.google.com/storage/docs/json_api/v1/buckets/insert
We should also provide listing, deletion, etc. Adding this to M2.
That's a good point. What API can we use that makes sense for that?
The following suggestion would require creating a
Bucketsinstance, which is how you get through to an individual bucket, of the current typeBucket.var storage = gcloud.storage; var buckets = new storage.Buckets(/*credentials*/); // buckets instanceof Buckets buckets.list(function(err, buckets) { // buckets = Bucket[] }); buckets.get('Photos', function(err, photos) { // photos instanceof Bucket }); buckets.create('Albums', function(err, albums) { // albums instanceof Bucket });
new storage.Bucketsmay sound a little weird, but I made it this way for these reasons:-
Our other APIs follow the
newinstantiation requirement -
We shouldn't have to provide connection details to more than one bucket. By defining this once when we create a
Bucketsinstance, we don't have to worry about this. As opposed to...var photos = new Bucket({ credentials: {} }); var albums = new Bucket({ credentials: {} });
-
I'm not a big fan of
newin API clients (take a look atgoogle-api-nodejs-clientand you'll see I try to avoid it).It does make sense to specify options only once so I think we should do that. But what about even sooner than Buckets? The credentials themselves should work for all gcloud apis, right?
So what about something radical like:
var gcloud = require('gcloud'); var client = new gcloud.Client({ credentials: /* ... */ }); // or just gcloud.options({ credentials: /* ... */ }); var storage = client.storage; // or just gcloud.storage if we use .options() example above storage.buckets.list(function(err, buckets) { var photos = buckets.get('Photos'); if(!photos) { buckets.create('Photos', function(err, photos) { photos.upload('funnycat.gif', { /* opts */ }, function(err) { console.log(err || 'Uploaded funny cat gif'); }); }); } });
What calls need to be async here?
buckets.create('Albums')sounds like it needs to be async.I'm not a big fan of new in API clients (take a look at google-api-nodejs-client and you'll see I try to avoid it).
You won't catch it in any of my stuff, either. I would like to argue that
newdoesn't make sense here, but I just can't. We're creating multiple instances of an object in the most light-weight way possible. This isn't to say it's right for my theory API above, but in general, I support it where we use it in this library.But what about even sooner than Buckets?
If we can do this, I like this much better. I'll have to read through this again for a refresher, but #46 (comment) was a blocker.
What calls need to be async here? buckets.create('Albums') sounds like it needs to be async.
createandgetfrom my example should have been async. I've updated it.I'm not saying using
newdoesn't make sense because it totally does, but I don't want the end-developer to worry about using it.newis used in the other client to create every endpoint but that is hidden, and what's exposed to the developer is simplyvar drive = google.drive('v2');instead ofvar drive = new google.Drive('v2');. I should be able to call on the api by just passing in names and ids, not creating objects and 'saving' them or doing weird operations on them. It should be as easy as:require('gcloud') .options({ credentials: require('./key.json') }) .storage .createBucket('bucket name', callback);
The more you hate on it, the more I agree with you. It feels like forcing the developer to use
newis important for them to understand "you're getting a new object that is meant to be multiply instantiated," but I suppose you can argue that that's an implementation detail of how our internal structure works, and sayinggcloud.datastore.dataset(), for example, can be just as clear, especially with the help of the documentation.* I'll recap this in #172, then we can seek opinions of others if and when we can implement it.require('gcloud') .options({ credentials: require('./key.json') })
This stuff should probably be talked about in a separate thread (perhaps the one I linked before). For now, we should just talk about how we can implement the Buckets api in our current structure. If and when we can support something like the above example, that will require a whole revamp of our code anyway.
* Sorry for the long sentence, but if anyone deserves that, it's you :P (just kidding of course)
Haha sorry, I ramble sometimes. But I really want this API client to be something we don't even have to teach developers to use. For storage, there's only a few key concepts we need to teach them: auth, buckets, files. Then the documentation will show them all the methods they can run on those concepts i.e. list buckets, upload file, list files, delete bucket, etc..
We can give them a couple examples and they can run with it. I want developers to be able to correctly GUESS how our client works, that's how easy it should be 😄 It's a lot to ask, but I think we can do it.
Current example (from our docs):
var gcloud = require('gcloud'); var storage = gcloud.storage; var bucket; // From Google Compute Engine: bucket = new storage.Bucket({ bucketName: YOUR_BUCKET_NAME }); // Or from elsewhere: bucket = new storage.Bucket({ bucketName: YOUR_BUCKET_NAME, keyFilename: '/path/to/the/key.json' }); bucket.write('demo.txt', 'Hello World', function(err) { console.log(err || 'Created demo.txt'); });
Could be simplified to:
var gcloud = require('gcloud'); gcloud.options({ keyFilename: !ON_COMPUTE && '/path/to/the/key.json' }); // some env variable used here to detect if you're on GCE var storage = gcloud.storage; storage.bucket('ryans-notes').write('demo.txt', 'Hello World', function(err) { console.log(err || 'Created demo.txt'); });
As an aside, if we made these changes, it would start to look and act a lot more like
google-api-nodejs-client, making a developer's transition from one library to another less painful.This library has the added benefit that we can hand-craft the api structure instead of having to tweak a bunch of templates and push it through a code generator (which is a huge pain the ass and requires a lot design upfront). I'm trying to bring those "design upfront" ideas here because it helps save a lot of time but we can still iterate and tweak as needed with more flexibility.
(That was a long aside) 😳
I see this as two separate discussions. Part 1 being allowing creation of a connected gcloud object, and Part 2 being how we can expand the Storage api we offer. I think it would make sense to continue Part 1 in the place where it left off: #46 and we can put Part 2 on hold if you think Part 1 needs to be resolved first.
storage.bucket('ryans-notes').write('demo.txt', 'Hello World', function(err) { console.log(err || 'Created demo.txt'); });
I really like the simplicity here. This way behaves as it does currently, as far as waits for the call to
writeto see that it would throw if that bucket doesn't exist. And that's ok, if we're ok with that. But, I was starting to like what we were working towards earlier in this thread, by getting that error immediately before thinking that you can get away with awrite:// assuming `stephen-notes` doesn't exist... var bucket = storage.bucket('stephen-notes'); ['things', 'to', 'write', 'to', 'my', 'secret', 'journal'].forEach(function(note) { bucket.write(note, function(err) { // 7 api calls and fails. }); }); // vs.. storage.bucket('stephen-notes', function(err, bucket) { if (err) { // don't waste time thinking bucket operations will work return; } // make api calls that will work. });
Any thoughts on all that? Should we allow assuredness while getting a bucket that it exists, or is it ok to continue to wait until the API calls?
As a note, when we allow creation of buckets, what method name should we use?
storage.bucketdoesn't make it clear to me if I'm creating or getting.I see this as two separate discussions.
Opened #191 for
gcloud.options()by getting that error immediately before thinking that you can get away with a write
Are you saying that
new storage.Bucket({ bucketName: 'ryan-notes' });would make a request to the API synchronously? You seem to be implying there is checking currently but I can't see that being the case.Should we allow assuredness while getting a bucket that it exists, or is it ok to continue to wait until the API calls?
Can we support both? If you supply a callback, make the request and callback a success/fail. Don't supply a callback, then assume it exists and create the bucket only locally.
We can also supply methods to check if a bucket exists / create a bucket so they can do the callback step themselves. Then storage.bucket(name) is just way to define what bucket we want to perform actions on, and yes we will receive errors if the bucket doesn't exist or they don't have permission.
storage.bucket('stephen-notes').exists(function(nope) { if(nope) { storage.bucket('stephen-notes').create(function(err, created) { storage.bucket('stephen-notes').upload(filename, callback); }); } else { storage.bucket('stephen-notes').upload(filename, callback); } });
Are you saying that new storage.Bucket({ bucketName: 'ryan-notes' }); would make a request to the API synchronously?
Yeah, to verify the bucket exists, and prevent future api calls to fail. It's going to fail eventually, might as well fail when the user tries to access a bucket is my thought, so they can address the issue before making possibly multiple failure calls to
writeand other methods.You seem to be implying there is checking currently but I can't see that being the case.
No, I said we don't do it currently. Just asking your opinion on if you think it's important.
As far as
exists, I think that's creating more complication than is necessary. We should either do it or not. Supporting both will lead to maintenance/documentation/support headaches.To be less harsh on
exists, it's a perfectly valid suggestion, so we can still see what others think.And just another note on it, since I just noticed this,
storage.bucket('stephen-notes').create()is pretty confusing to me. I think we should have a top level method onstorageto create a bucket, as opposed to this, where we think we get a bucket, but then have to call create.Now that I think about it, I really prefer using
storage.bucket(name)as an encapsulation object that we perform methods on. So we should providestorage.bucket(name).exists(callback)but we just assume the developer will use it to check if they are unsure. If a developer KNOWS the bucket exists, we shouldn't force them to use an API call to check. In this case, we also have very minimal overhead in creating a bucket object too. 👍67 remaining items
- added a commit that references this issue
on Feb 17, 2026 - added a commit that references this issue
on Mar 5, 2026 - added a commit that references this issue
on Mar 12, 2026 - added a commit that references this issue
on Mar 18, 2026 - added a commit that references this issue
on Mar 27, 2026 - added a commit that references this issue
on Mar 27, 2026 - added a commit that references this issue
on May 5, 2026
Our README says that we must create a bucket on the developers console before we can use it in this library. Can't we provide a method to allow developers to create buckets on the fly?