Skip to content

Commit 012ca02

Browse files
authored
feat: docs for sdk multipart (#279)
1 parent 079ab0d commit 012ca02

File tree

3 files changed

+142
-15
lines changed

3 files changed

+142
-15
lines changed

docs/sdks/tigris/client-uploads.mdx

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,27 @@ import { upload } from "@tigrisdata/storage/client";
3131

3232
#### `options`
3333

34-
| **Parameter** | **Required** | **Values** |
35-
| ---------------- | ------------ | ----------------------------------------------------------------------------------------------------------- |
36-
| url | No | The URL to upload the file to. |
37-
| access | No | The access level for the object. Possible values are `public` and `private`. |
38-
| onUploadProgress | No | Callback to track upload progress: `onUploadProgress({loaded: number, total: number, percentage: number})`. |
39-
| config | No | A configuration object to override the [default configuration](/docs/sdks/tigris/using-sdk#authentication). |
34+
| **Parameter** | **Required** | **Values** |
35+
| ------------------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
36+
| url | Yes | The URL to backend endpoint where Storage SDK is running on server. |
37+
| access | No | The access level for the object. Possible values are `public` and `private`. |
38+
| addRandomSuffix | No | Whether to add a random suffix to the object name. Default is `false`. |
39+
| contentType | No | The content type of the object. |
40+
| contentDisposition | No | The content disposition of the object. Possible values are `inline` and `attachment`. Default is `inline`. Use `attachment` for downloadable files. |
41+
| multipart | No | Pass `multipart: true` when uploading large objects. It will split the object into multiple parts and upload them in parallel. |
42+
| partSize | No | The size of the part to upload. Default is `5 * 1024 * 1024` (5 MiB). |
43+
| onUploadProgress | No | Callback to track upload progress: `onUploadProgress({loaded: number, total: number, percentage: number})`. |
44+
| config | No | A configuration object to override the [default configuration](/docs/sdks/tigris/using-sdk#authentication). |
45+
46+
In case of successful upload, the `data` property will be set to the upload and
47+
contains the following properties:
48+
49+
- `contentDisposition`: content disposition of the object
50+
- `contentType`: content type of the object
51+
- `modified`: Last modified date of the object
52+
- `path`: Path to the object
53+
- `size`: Size of the object
54+
- `url`: A presigned URL to the object
4055

4156
### Example
4257

@@ -49,6 +64,7 @@ import { upload } from "@tigrisdata/storage/client";
4964
upload("file.txt", file, {
5065
url: "/api/upload",
5166
access: "private",
67+
multipart: true,
5268
onUploadProgress: ({ loaded, total, percentage }) => {
5369
console.log(`Uploaded ${loaded} of ${total} bytes (${percentage}%)`);
5470
},

docs/sdks/tigris/examples.mdx

Lines changed: 117 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ some ready examples available at
99
Something missing there that you you'd like to see? Let us know and we'll be
1010
more than happy to add in examples.
1111

12-
### Viewing and downloading files
12+
## Viewing and downloading files
1313

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

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

85-
### Uploading files
85+
## Uploading files
8686

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

@@ -140,7 +140,7 @@ export default function Upload() {
140140
</TabItem>
141141
</Tabs>
142142

143-
### Client Uploads
143+
## Client Uploads
144144

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

155+
### Multipart upload
156+
157+
<Tabs>
158+
<TabItem value="server" label="Server" default>
159+
160+
```ts
161+
// app/api/upload/route.ts
162+
import { NextRequest, NextResponse } from "next/server";
163+
import {
164+
initMultipartUpload,
165+
getPartsPresignedUrls,
166+
completeMultipartUpload,
167+
UploadAction,
168+
} from "@tigrisdata/storage";
169+
170+
export async function POST(request: NextRequest) {
171+
try {
172+
const { path, operation, action, contentType, uploadId, parts, partIds } =
173+
await request.json();
174+
175+
switch (action) {
176+
case UploadAction.MultipartInit: {
177+
const result = await initMultipartUpload(path, {});
178+
return NextResponse.json({ data: result.data });
179+
}
180+
181+
case UploadAction.MultipartGetParts: {
182+
if (!uploadId || !parts) {
183+
return NextResponse.json(
184+
{ error: "uploadId and parts are required for multipart-parts" },
185+
{ status: 400 },
186+
);
187+
}
188+
const result = await getPartsPresignedUrls(path, parts, uploadId, {});
189+
return NextResponse.json({ data: result.data });
190+
}
191+
192+
case UploadAction.MultipartComplete:
193+
{
194+
if (!uploadId) {
195+
return NextResponse.json(
196+
{ error: "uploadId is required for multipart-complete" },
197+
{ status: 400 },
198+
);
199+
}
200+
const result = await completeMultipartUpload(path, uploadId, partIds);
201+
return NextResponse.json({ data: result.data });
202+
}
203+
204+
return NextResponse.json(
205+
{ error: `Unsupported action: ${action}` },
206+
{ status: 400 },
207+
);
208+
}
209+
} catch (error) {
210+
return NextResponse.json(
211+
{ error: "Failed to process upload request" },
212+
{ status: 500 },
213+
);
214+
}
215+
}
216+
```
217+
218+
</TabItem>
219+
220+
<TabItem value="client" label="Client">
221+
222+
```tsx
223+
"use client";
224+
225+
import { upload } from "@tigrisdata/storage/client";
226+
import { useState } from "react";
227+
228+
export default function ClientUpload() {
229+
const [progress, setProgress] = useState<number>(0);
230+
const [url, setUrl] = useState<string | null>(null);
231+
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
232+
const file = e.target.files?.[0];
233+
setProgress(0);
234+
if (file) {
235+
const result = await upload(`${file.name}`, file, {
236+
url: "/api/upload",
237+
access: "private",
238+
multipart: true,
239+
partSize: 10 * 1024 * 1024, // 10 MiB parts
240+
onUploadProgress: ({ loaded, total, percentage }) => {
241+
setProgress(percentage);
242+
if (percentage === 100) {
243+
setProgress(0);
244+
}
245+
},
246+
});
247+
setUrl(result.url);
248+
}
249+
};
250+
251+
return (
252+
<>
253+
<input type="file" onChange={handleFileChange} />{" "}
254+
{url && <div>Uploaded to: {url}</div>}{" "}
255+
{progress > 0 && progress < 100 && <div>{progress}%</div>}{" "}
256+
</>
257+
);
258+
}
259+
```
260+
261+
</TabItem>
262+
263+
</Tabs>
264+
265+
### Simple upload
266+
155267
<Tabs>
156268
<TabItem value="server" label="Server" default>
157269

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

163275
export async function POST(request: NextRequest) {
164276
try {
165-
const { path, method, contentType } = await request.json();
277+
const { path, contentType } = await request.json();
166278
const result = await getPresignedUrl(path, {
167-
method,
168-
contentType,
279+
operation: "put",
169280
expiresIn: 3600, // 1 hour
170281
});
171282

docs/sdks/tigris/using-sdk.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ getPresignedUrl(path: string, options: GetPresignedUrlOptions): Promise<TigrisSt
365365

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

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

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

396396
```ts
397-
const result = await getPresignedUrl("object.txt", { method: "put" });
397+
const result = await getPresignedUrl("object.txt", { operation: "put" });
398398
```
399399

400400
## Listing objects

0 commit comments

Comments
 (0)