Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: response.base64() #1800

Open
hemanth opened this issue Jan 8, 2025 · 5 comments
Open

Proposal: response.base64() #1800

hemanth opened this issue Jan 8, 2025 · 5 comments
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest topic: api

Comments

@hemanth
Copy link

hemanth commented Jan 8, 2025

What problem are you trying to solve?

Problem Statement

Currently, when working with the Fetch API, converting response data to base64 encoding requires multiple steps and introduces complexity, especially when handling binary data. Developers often need to:

  1. Read the response as a blob or array buffer
  2. Convert it to base64 using additional utilities
  3. Handle potential encoding issues

This process is error-prone and requires additional code that could be standardized.

What solutions exist today?

Existing Solutions

Currently, developers typically handle this in one of these ways:

  1. Using FileReader:
const response = await fetch(url);
const blob = await response.blob();
const reader = new FileReader();
reader.readAsDataURL(blob);
await new Promise(resolve => reader.onload = resolve);
const base64 = reader.result.split(',')[1];
  1. Using array buffers and manual conversion:
const response = await fetch(url);
const buffer = await response.arrayBuffer();
const bytes = new Uint8Array(buffer);
const binary = bytes.reduce((data, byte) => data + String.fromCharCode(byte), '');
const base64 = btoa(binary);

Both approaches have drawbacks:

  • Verbose and complex code
  • Performance overhead from multiple conversions
  • Inconsistent handling across different types of content
  • Memory inefficient due to multiple data copies

How would you solve it?

Proposed Solution

Add a new method base64() to the Response prototype:

interface Response {
  base64(): Promise<string>;
}

Example usage:

const response = await fetch('https://example.com/image.png');
const base64Data = await response.base64();

Implementation Details

The method would:

  1. Efficiently read the response body
  2. Convert it directly to base64 encoding
  3. Return a Promise that resolves with the base64 string

Benefits

  1. Simplicity: Single method call instead of complex conversion chains
  2. Performance: Native implementation can optimize the conversion process
  3. Memory efficiency: Avoid unnecessary intermediate copies
  4. Standardization: Consistent behavior across browsers
  5. Error handling: Built-in handling of encoding edge cases

Compatibility

The method name base64() is not currently used in the Response prototype, making it safe to add. The method would return a Promise to maintain consistency with other Response body reading methods.

Additional Considerations

Security

  • The method should respect same-origin policies
  • Large responses should be handled efficiently to prevent memory issues
  • Consider adding optional parameters for handling different encodings

Edge Cases

  • Handle empty responses
  • Consider adding options for URL-safe base64 encoding
  • Define behavior for streaming responses

Performance Impact

  • Native implementation can optimize the conversion process
  • Consider chunked processing for large responses
  • Potential for WebAssembly acceleration

Anything else?

Open Questions

  1. Should there be a size limit for automatic base64 conversion?
  2. Should streaming be supported for large responses?
  3. Should there be options for different base64 variants (standard, URL-safe)?
@hemanth hemanth added addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest labels Jan 8, 2025
@ljharb
Copy link

ljharb commented Jan 8, 2025

I think now it'd be bytes.toBase64() in your 2nd example there?

@nektro
Copy link

nektro commented Jan 8, 2025

related https://github.com/tc39/proposal-arraybuffer-base64

@ljharb
Copy link

ljharb commented Jan 8, 2025

Having await response.base64() (where it takes the same options that ArrayBuffer.prototype.toBase64` does) seems fine

@hemanth
Copy link
Author

hemanth commented Jan 8, 2025

Yes, was following proposal-arraybuffer-base64 but again we would still need to do a new Uint8Array(await response.arrayBuffer()).toBase64() rather response.base64() is convenient and intuitive.

@annevk
Copy link
Member

annevk commented Jan 9, 2025

(await response.bytes()).toBase64() is pretty short. If a lot of code ends up doing that maybe we should provide a shortcut, but let's wait a couple of years for the other APIs to become more readily available to see if there's actually such a trend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest topic: api
Development

No branches or pull requests

4 participants