Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Simple file upload doesn't respect apiEndpoint #898

Closed

Description

@chrisrecalis

File uploading does not respect apiEndpoint or the environment variable STORAGE_EMULATOR_HOST. Instead it uses a hardcoded constant STORAGE_UPLOAD_BASE_URL

Environment details

  • OS: Mac 10.14.6
  • Node.js version: 12.12.0
  • npm version: 6.11.3
  • @google-cloud/storage version: 4.0.0

Activity

  1. changed the title [-]File upload & downloading don't respect apiEndpoint[/-] [+]Simple file upload doesn't respect apiEndpoint[/+] on Oct 24, 2019
  2. chrisrecalis commented on Oct 24, 2019

    @chrisrecalis
    Author

    After a little investigation I can see why it was done this way:

    In @google-cloud/common the ServiceObject function request_ builds a uri based on the object id and its parent id. Unless an absolute URL is provided. If the absolute URL wasn't provided in

    nodejs-storage/src/file.ts

    Lines 3398 to 3403 in f2d567f

    const reqOpts: DecorateRequestOptions = {
    qs: {
    name: this.name,
    },
    uri: `${STORAGE_UPLOAD_BASE_URL}/${this.bucket.name}/o`,
    };

    The request uri would build to be something like https://{apiEndpoint}/storage/v1/b/my-bucket/o/myfile.txt when trying to upload a file myfile.txt. Which doesn't conform to https://cloud.google.com/storage/docs/json_api/v1/objects/insert.

    I've since just used an interceptor instead:

    const storage = new Storage({
        projectId: 'test'
    });
    
    storage.interceptors.push({
        request: function(reqOpts) {
            const url = new URL(reqOpts.uri)
            url.host = "127.0.0.1:4443"
            reqOpts.uri = url.toString()
            return reqOpts
        }
    })
  3. stephenplusplus commented on Oct 24, 2019

    @stephenplusplus
    Contributor

    Thanks for digging into that, and sharing the solution you found! Is STORAGE_EMULATOR_HOST an official env var? That follows the format from Datastore, although unlike Datastore, I haven't found an official Storage API emulator.

    @frankyn what is the extent of support we want to provide for this use case?

  4. chrisrecalis commented on Oct 24, 2019

    @chrisrecalis
    Author

    I'm currently using fake-gcs-server as my emulator. The environment variable was dug up in source code:

    constructor(options: StorageOptions = {}) {
    options.apiEndpoint = options.apiEndpoint || 'www.googleapis.com';
    const url =
    process.env.STORAGE_EMULATOR_HOST ||
    `https://${options.apiEndpoint}/storage/v1`;

  5. chrisrecalis commented on Oct 24, 2019

    @chrisrecalis
    Author

    Would it work if it followed the same creation method as Buckets? ie the bucket.create() method calls the Service.createBucket method. If a File called Bucket.createFile(aka startSimpleUpload_) then when the uri is built inside Bucket.request({ uri: '/o' }) it would end up building the correct url.

  6. frankyn commented on Oct 24, 2019

    @frankyn
    Contributor

    @stephenplusplus, STORAGE_EMULATOR_HOST env var was introduced for benchmarking by @jadekler. We don't have an official GCS emulator at the moment.

    IIUC, STORAGE_EMULATOR_HOST should have the same effect as setting apiEndpoint.

  7. stephenplusplus commented on Oct 24, 2019

    @stephenplusplus
    Contributor

    Ah, nice, I didn't know that slipped in there. I think we can figure this out. I'll assign to myself and update everyone accordingly for reviews!

  8. added
    priority: p2Moderately-important priority. Fix may not be included in next release.
    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.
    and removed
    type: questionRequest for information or clarification. Not an issue.
    on Oct 24, 2019
  9. stephenplusplus commented on Oct 29, 2019

    @stephenplusplus
    Contributor

    @frankyn In our other APIs, options.apiEndpoint and the corresponding emulator environment variable are expected to have the same side effects when set-- everything is appended to that "base" URL.

    Currently in Storage, however, the emulator environment variable replaces https://storage.googleapis.com/storage/v1, while options.apiEndpoint only replaces storage.googleapis.com.

    Since options.apiEndpoint was designed for the same purpose as the environment variable and STORAGE_EMULATOR_HOST isn't an official environment variable, can we rethink this to have both behave equally?

    In any case, what would be the correct URL to send the upload request to:

    1. https://${userProvidedOverride}/upload/storage/v1/b/${this.bucket.name}/o
    2. https://${userProvidedOverride}/b/${this.bucket.name}/o (the /upload/ prefix removed, otherwise /storage/v1/ is duplicated)

    Hope this made sense!

  10. jkwlui commented on Nov 7, 2019

    @jkwlui
    Contributor

    @frankyn let me know if you think otherwise:

    I think we should keep upload requests at the /upload endpoint, as-per GCS documentation. For the particular use case of fake-gcs-server by @chrisrecalis, this endpoint is supported.

    +1 to STORAGE_EMULATOR_HOST mapping to options.apiEndpoint, question is which one should take precedence?

  11. yannickadam commented on Mar 20, 2020

    @yannickadam

    If this can help anyone, the workaround provided will not work with:
    File.createWriteStream() as it uses startResumableUpload_ instead of startSimpleUpload_.
    You can use File.createWriteStream({resumable: false}) in the meantime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

🚨This issue needs some love.api: storageIssues related to the googleapis/nodejs-storage API.priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions