Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
11 changes: 11 additions & 0 deletions docs/sdks/tigris/client-uploads.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ import { upload } from "@tigrisdata/storage/client";
| onUploadProgress | No | Callback to track upload progress: `onUploadProgress({loaded: number, total: number, percentage: number})`. |
| config | No | A configuration object to override the [default configuration](/docs/sdks/tigris/using-sdk#authentication). |

In case of successful upload, the `data` property will be set to the upload and
contains the following properties:

- `contentDisposition`: content disposition of the object
- `contentType`: content type of the object
- `modified`: Last modified date of the object
- `path`: Path to the object
- `size`: Size of the object
- `url`: A presigned URL to the object

### Example

```html
Expand All @@ -49,6 +59,7 @@ import { upload } from "@tigrisdata/storage/client";
upload("file.txt", file, {
url: "/api/upload",
access: "private",
multipart: true,
onUploadProgress: ({ loaded, total, percentage }) => {
console.log(`Uploaded ${loaded} of ${total} bytes (${percentage}%)`);
},
Expand Down
123 changes: 117 additions & 6 deletions docs/sdks/tigris/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ some ready examples available at
Something missing there that you you'd like to see? Let us know and we'll be
more than happy to add in examples.

### Viewing and downloading files
## Viewing and downloading files

`get` function can be used to get a file from a bucket. `contentDisposition`
option can be to either `attachment` or `inline` depending on whether you want
Expand Down Expand Up @@ -82,7 +82,7 @@ export default function Avatar() {

To trigger a download, set the `contentDisposition` option to `attachment`.

### Uploading files
## Uploading files

`put` function can be used to upload a file to a bucket.

Expand Down Expand Up @@ -140,7 +140,7 @@ export default function Upload() {
</TabItem>
</Tabs>

### Client Uploads
## Client Uploads

Tigris does not charge egress fees, but your hosting provider may charge them
for user uploads to Tigris. We care about your bandwidth costs, so we made it
Expand All @@ -152,6 +152,118 @@ We leverage the
[presigned URLs](/docs/sdks/tigris/using-sdk#presigning-an-object) features to
allow you to upload files directly to Tigris from the client side.

### Multipart upload

<Tabs>
<TabItem value="server" label="Server" default>

```ts
// app/api/upload/route.ts
import { NextRequest, NextResponse } from "next/server";
import {
initMultipartUpload,
getPartsPresignedUrls,
completeMultipartUpload,
UploadAction,
} from "@tigrisdata/storage";

export async function POST(request: NextRequest) {
try {
const { path, operation, action, contentType, uploadId, parts, partIds } =
await request.json();

switch (action) {
case UploadAction.MultipartInit: {
const result = await initMultipartUpload(path, {});
return NextResponse.json({ data: result.data });
}

case UploadAction.MultipartGetParts: {
if (!uploadId || !parts) {
return NextResponse.json(
{ error: "uploadId and parts are required for multipart-parts" },
{ status: 400 },
);
}
const result = await getPartsPresignedUrls(path, parts, uploadId, {});
return NextResponse.json({ data: result.data });
}

case UploadAction.MultipartComplete: {
if (!uploadId) {
return NextResponse.json(
{ error: "uploadId is required for multipart-complete" },
{ status: 400 },
);
}
const result = await completeMultipartUpload(path, uploadId, partIds);
return NextResponse.json({ data: result.data });
}

default:
return NextResponse.json(
{ error: `Unsupported operation: ${operation}` },
{ status: 400 },
);
}
} catch (error) {
return NextResponse.json(
{ error: "Failed to process upload request" },
{ status: 500 },
);
}
}
```

</TabItem>

<TabItem value="client" label="Client">

```tsx
"use client";

import { upload } from "@tigrisdata/storage/client";
import { useState } from "react";

export default function ClientUpload() {
const [progress, setProgress] = useState<number>(0);
const [url, setUrl] = useState<string | null>(null);
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
setProgress(0);
if (file) {
const result = await upload(`${file.name}`, file, {
url: "/api/upload",
access: "private",
multipart: true,
partSize: 10 * 1024 * 1024, // 10 MiB parts
onUploadProgress: ({ loaded, total, percentage }) => {
setProgress(percentage);
if (percentage === 100) {
setProgress(0);
}
},
});
setUrl(result.url);
}
};

return (
<>
<input type="file" onChange={handleFileChange} />{" "}
{url && <div>Uploaded to: {url}</div>}{" "}
{progress > 0 && progress < 100 && <div>{progress}%</div>}{" "}
</>
);
}
```

</TabItem>

</Tabs>

### Simple upload

<Tabs>
<TabItem value="server" label="Server" default>

Expand All @@ -162,10 +274,9 @@ import { getPresignedUrl } from "@tigrisdata/storage";

export async function POST(request: NextRequest) {
try {
const { path, method, contentType } = await request.json();
const { path, contentType } = await request.json();
const result = await getPresignedUrl(path, {
method,
contentType,
operation: "put",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be PUT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not, it's lower-case put

expiresIn: 3600, // 1 hour
});

Expand Down
6 changes: 3 additions & 3 deletions docs/sdks/tigris/using-sdk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ getPresignedUrl(path: string, options: GetPresignedUrlOptions): Promise<TigrisSt

| **Parameter** | **Required** | **Values** |
| ------------- | ------------ | ---------------------------------------------------------------------------------------- |
| method | No | Specify the operation to use for the presigned URL. Possible values are `get` and `put`. |
| operation | No | Specify the operation to use for the presigned URL. Possible values are `get` and `put`. |
| expiresIn | No | The expiration time of the presigned URL in seconds. Default is 3600 seconds (1 hour). |
| contentType | No | The content type of the object. |
| config | No | A configuration object to override the [default configuration](#authentication). |
Expand All @@ -382,7 +382,7 @@ presigned URL and contains the following properties:
#### Get a presigned URL for a GET operation

```ts
const result = await getPresignedUrl("object.txt", { method: "get" });
const result = await getPresignedUrl("object.txt", { operation: "get" });

if (result.error) {
console.error("Error getting presigned URL:", result.error);
Expand All @@ -394,7 +394,7 @@ if (result.error) {
#### Get a presigned URL for a PUT operation

```ts
const result = await getPresignedUrl("object.txt", { method: "put" });
const result = await getPresignedUrl("object.txt", { operation: "put" });
```

## Listing objects
Expand Down