Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions handwritten/storage/MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Storage v7 to v8 Migration Guide - Node.js 18 & Gaxios Update

This guide helps you migrate your application from `@google-cloud/storage` v7 to v8, focusing on the transition to Node.js 18+ as the minimum supported environment and changes introduced by updating the underlying HTTP client, `gaxios`, to version 7.

## Minimum Requirements: Node.js 18

`@google-cloud/storage` v8 now officially requires Node.js 18 or higher. This update aligns the library with modern JavaScript environments.

Specifically, Node.js 18 introduced native global Web APIs (such as `fetch` and `Headers`). Conforming to this standard, the underlying HTTP client, `gaxios` (updated to v7), leverages native `Headers` rather than custom user-land header representations. As a result, `@google-cloud/storage` v8 has transitioned response and request headers to standard native global `Headers` objects.


## Key Breaking Changes for Storage Users

### 1. Response Headers are now `Headers` objects

When you receive a full API response from Storage methods (e.g., via callbacks or promise resolutions that include the response object), the `headers` property of the response is now a standard native `Headers` object (aligned with the Fetch API standard in Node.js 18) rather than a plain JavaScript object.

**Before (Storage v7):**

```js
const [retrievedFile, apiResponse] = await file.get();
const contentType = apiResponse.headers['content-type'];
```

**After (Storage v8):**

```js
const [retrievedFile, apiResponse] = await file.get();
// Accessing headers requires the .get() method
const contentType = apiResponse.headers.get('content-type');
```

### 2. Passing Headers in Options

If you pass custom headers in options to Storage methods (which extend `GaxiosOptions`), you can still pass plain objects, as the Storage library will convert them to standard `Headers` internally for the request. However, if you read them back from the prepared options or response, they will be `Headers` objects.

**Before (Storage v7):**

```js
// Reading request headers back from response metadata returned a plain object
const customHeader = apiResponse.config.headers['x-custom-header'];
```

**After (Storage v8):**

```js
// Reading request headers back from response metadata requires .get()
const customHeader = apiResponse.config.headers.get('x-custom-header');
```

> [!WARNING]
> **Header Value Stringification:** Plain JavaScript objects allow passing non-string values (such as arrays or numbers) which are implicitly processed. However, the native `Headers` constructor strictly converts all values to standard string representations. For example, passing an array of values (e.g., `['val1', 'val2']`) will result in a single comma-separated string (e.g., `'val1, val2'`). Ensure you pre-format or verify your header values before passing them to custom options.


### 3. URL Resolution (`baseURL`)

If you are using custom `baseURL` options or passing relative URLs to methods that accept them, be aware that resolution now strictly follows the standard native `URL` constructor spec (`new URL(url, baseURL)`). This can affect how leading slashes in paths resolve.

**Before (Storage v7):**

Using standard path-joining custom resolution:
- `baseURL`: `https://storage.googleapis.com/storage/v1`
- `url`: `/b/my-bucket`
- Resolved URL: `https://storage.googleapis.com/storage/v1/b/my-bucket`

**After (Storage v8):**

Strictly resolved via the standard native `URL` constructor rules (where a leading slash resolves relative to the root of the host):
- `baseURL`: `https://storage.googleapis.com/storage/v1`
- `url`: `/b/my-bucket`
- Resolved URL: `https://storage.googleapis.com/b/my-bucket` (resolves relative to host root, stripping `storage/v1`)


## Upgrade Instructions

Update your `@google-cloud/storage` dependency to version 8:

```sh
npm install @google-cloud/storage@latest
```

## Troubleshooting

- If you encounter `undefined` when accessing headers on the response object, ensure you are using `apiResponse.headers.get('header-name')`.
Loading