Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions .github/workflows/accessibility_scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
uses: ./.github/actions/set_yarn_berry
- name: Install dependencies
run: yarn
- name: Install Chrome for Puppeteer
run: npx puppeteer browsers install chrome
- name: Build
run: yarn build
env:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
uses: ./.github/actions/set_yarn_berry
- name: Install Dependencies
run: yarn
- name: Install Chrome for Puppeteer
run: npx puppeteer browsers install chrome
- name: Run tests
run: yarn prebuild && yarn test:unit
- name: Run Build
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/check_for_console_errors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
uses: ./.github/actions/set_yarn_berry
- name: Install Dependencies
run: yarn
- name: Install Chrome for Puppeteer
run: npx puppeteer browsers install chrome
- name: Run Build
run: yarn build:release
env:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/check_pr_for_broken_links.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
uses: ./.github/actions/set_yarn_berry
- name: Install Dependencies
run: yarn
- name: Install Chrome for Puppeteer
run: npx puppeteer browsers install chrome
- name: Run Build
run: yarn build
env:
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -1527,6 +1527,7 @@
"CHALLENGEANSWER",
"Fargate",
"Dockerizing",
"duckdb",
"WORKDIR",
"endregion",
"entrypoint",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,5 @@
"overrides": {
"tmp": "^0.2.4"
},
"packageManager": "yarn@4.9.0"
"packageManager": "yarn@4.14.1"
}
17 changes: 13 additions & 4 deletions src/pages/[platform]/frontend/storage/download-files/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ const linkToStorageFile = await getUrl({

Option | Type | Default | Description |
| :--: | :--: | :--: | ----------- |
| method | 'GET' \| 'PUT' | 'GET' | The HTTP method for the presigned URL. `'GET'` generates a URL for downloading an object. `'PUT'` generates a URL for uploading an object. <br/><br/> Read more at [Upload using a presigned URL](/[platform]/frontend/storage/upload-files/#upload-using-a-presigned-url) |
| bucket | string \| <br />\{ bucketName: string;<br/> region: string; \} | Default bucket and region from Amplify configuration | A string representing the target bucket's assigned name in Amplify Backend or an object specifying the bucket name and region from the console.<br/><br/>Read more at [Configure additional storage buckets](/[platform]/build-a-backend/storage/set-up-storage/#configure-additional-storage-buckets)
| validateObjectExistence | boolean | false | Whether to head object to make sure the object existence before downloading. |
| expiresIn | number | 900 | Number of seconds till the URL expires. <br/><br/> The expiration time of the presigned url is dependent on the session and will max out at 1 hour. |
Expand Down Expand Up @@ -279,10 +280,18 @@ let url = try await Amplify.Storage.getURL(

### All `getURL` options

Option | Type | Description |
| -- | -- | ----------- |
| expires | Int | Number of seconds before the URL expires |
| bucket | StorageBucket | The bucket in which the object is stored |
Option | Type | Default | Description |
| -- | -- | :--: | ----------- |
| expires | Int | 18000 | Number of seconds before the URL expires |
| bucket | StorageBucket | Default bucket from Amplify configuration | The bucket in which the object is stored |
| pluginOptions.method | StorageAccessMethod | .get | `.get` generates a download URL. `.put` generates an upload URL. |
| pluginOptions.validateObjectExistence | Bool | false | Whether to check the object exists before generating the URL. Skipped when method is `.put`. |

<Callout>

You can also use `getURL` with `method: .put` to generate presigned URLs for uploading files directly to S3. Learn more at [Upload using a presigned URL](/[platform]/frontend/storage/upload-files/#upload-using-a-presigned-url).

</Callout>

</InlineFilter>

Expand Down
137 changes: 137 additions & 0 deletions src/pages/[platform]/frontend/storage/upload-files/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,56 @@ func getTempUrls(securityScopedUrls: [URL]) -> [URL] {
}
```

## Upload using a presigned URL

You can use the `getURL` API with `method: .put` to generate a presigned URL for uploading files directly to S3. This is useful when:

- You need to integrate with third-party tools or libraries that only accept standard HTTP URL endpoints
- You want to share a temporary upload link with another client or service
- You need to upload from a context where the Amplify SDK is not available

```swift
import Amplify
import AWSS3StoragePlugin

// Generate a presigned URL for uploading
let uploadUrl = try await Amplify.Storage.getURL(
path: .fromString("public/uploads/photo.jpg"),
options: .init(
pluginOptions: AWSStorageGetURLOptions(
method: .put
)
)
)
```

Then use the presigned URL to upload the file with a standard HTTP `PUT` request:

```swift
var request = URLRequest(url: uploadUrl)
request.httpMethod = "PUT"
request.httpBody = imageData

let (_, response) = try await URLSession.shared.data(for: request)
let httpResponse = response as? HTTPURLResponse
print("Upload status: \(httpResponse?.statusCode ?? 0)")
```

<Callout warning>

When `method: .put` is specified, the `validateObjectExistence` option is ignored since the object may not exist yet.

</Callout>

### Presigned URL upload options

Option | Type | Default | Description |
| -- | -- | :--: | ----------- |
| pluginOptions.method | StorageAccessMethod | .get | `.get` generates a download URL. `.put` generates an upload URL. |
| expires | Int | 18000 | Number of seconds before the URL expires. |
| bucket | StorageBucket | Default bucket from Amplify configuration | The bucket in which the object is stored. |
| pluginOptions.validateObjectExistence | Bool | false | Whether to check the object exists before generating the URL. Skipped when method is `.put`. |

</InlineFilter>

<InlineFilter filters={["react", "angular", "javascript", "vue", "nextjs", "react-native"]}>
Expand Down Expand Up @@ -1642,3 +1692,90 @@ Uploads that were initiated over one hour ago will be cancelled automatically. T
## MultiPart upload

Amplify will automatically perform an Amazon S3 multipart upload for objects that are larger than 5MB. For more information about S3's multipart upload, see [Uploading and copying objects using multipart upload](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html)

<InlineFilter filters={["react", "angular", "javascript", "vue", "nextjs", "react-native"]}>

## Upload using a presigned URL

You can use the `getUrl` API with `method: 'PUT'` to generate a presigned URL for uploading files directly to S3. This is useful when:

- You need to integrate with third-party tools or libraries that only accept standard HTTP URL endpoints (e.g. DuckDB, database export tools)
- You want to upload from server-side environments such as Next.js API routes or other SSR frameworks
- You need to share a temporary upload link with another client or service

```typescript
import { getUrl } from 'aws-amplify/storage';

// Generate a presigned URL for uploading
const { url, expiresAt } = await getUrl({
path: 'album/2024/1.jpg',
options: {
method: 'PUT',
expiresIn: 3600, // URL valid for 1 hour
contentType: 'image/jpeg',
}
});

console.log('Upload URL: ', url);
console.log('URL expires at: ', expiresAt);
```

Then use the presigned URL to upload the file with a standard HTTP `PUT` request:

```typescript
await fetch(url, {
method: 'PUT',
body: file,
headers: {
'Content-Type': 'image/jpeg',
},
});
```

<Callout warning>

When `method: 'PUT'` is specified, the `validateObjectExistence` option is ignored since the object may not exist yet.

</Callout>

<Callout>

If you specify `contentType` when generating the presigned URL, you **must** include the matching `Content-Type` header in the upload request. A mismatch will cause S3 to reject the request with a signature error.

</Callout>

### Using presigned URLs with third-party tools

Because the presigned URL is a standard HTTP endpoint, it works with any tool that supports HTTP uploads:

```typescript
import { getUrl } from 'aws-amplify/storage';

const { url } = await getUrl({
path: 'analytics/data.parquet',
options: {
method: 'PUT',
contentType: 'application/octet-stream',
}
});

// Example: use with DuckDB to export query results directly to S3
await duckdb.query(`
COPY (SELECT * FROM processed_data)
TO '${url}'
(FORMAT PARQUET)
`);
```

### Presigned URL upload options

Option | Type | Default | Description |
| :--: | :--: | :--: | ----------- |
| method | 'GET' \| 'PUT' | 'GET' | The HTTP method for the presigned URL. Use `'PUT'` to generate an upload URL. |
| bucket | string \| <br />\{ bucketName: string;<br/> region: string; \} | Default bucket and region from Amplify configuration | A string representing the target bucket's assigned name in Amplify Backend or an object specifying the bucket name and region from the console.<br/><br/>Read more at [Configure additional storage buckets](/[platform]/build-a-backend/storage/set-up-storage/#configure-additional-storage-buckets) |
| expiresIn | number | 900 | Number of seconds till the URL expires. <br/><br/> The expiration time of the presigned url is dependent on the session and will max out at 1 hour. |
| contentType | string | — | The MIME type of the file to be uploaded. When specified, the matching `Content-Type` header must be included in the upload request. |
| contentDisposition | string \| object | — | Specifies presentational information for the object. Can be a string (e.g. `'attachment; filename="file.jpg"'`) or an object (e.g. `{ type: 'attachment', filename: 'file.jpg' }`). |
| expectedBucketOwner | string | — | The account ID that owns requested bucket. |

</InlineFilter>
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Manual changes might be lost - proceed with caution!

__metadata:
version: 8
version: 9
cacheKey: 10c0

"@aashutoshrathi/word-wrap@npm:^1.2.3":
Expand Down
Loading