File Operations
Resumable Upload (tus-style)
DownloadValidateExpert
Description
Upload a file in chunks, survive an interruption, and resume from the server-reported offset instead of starting over.
Test Scenario
// Playwright: upload 20 bytes in two chunks, then prove resume works
const create = await request.post('/api/v1/upload/resumable', {
headers: { 'Upload-Length': '20' },
});
expect(create.status()).toBe(201);
const id = new URL(create.headers()['location'], 'http://x').searchParams.get('id');
// First chunk
const first = await request.patch(`/api/v1/upload/resumable?id=${id}`, {
headers: { 'Upload-Offset': '0', 'Content-Type': 'application/offset+octet-stream' },
data: 'ABCDEFGHIJ',
});
expect(first.headers()['upload-offset']).toBe('10');
// Replaying the same offset is a stale write โ the server refuses it
const stale = await request.patch(`/api/v1/upload/resumable?id=${id}`, {
headers: { 'Upload-Offset': '0' },
data: 'XXXX',
});
expect(stale.status()).toBe(409);
// Ask the server where to resume, then finish
const head = await request.head(`/api/v1/upload/resumable?id=${id}`);
const offset = head.headers()['upload-offset'];
const second = await request.patch(`/api/v1/upload/resumable?id=${id}`, {
headers: { 'Upload-Offset': offset, 'Content-Type': 'application/offset+octet-stream' },
data: 'KLMNOPQRST',
});
expect(second.headers()['upload-offset']).toBe('20');Endpoint
/api/v1/upload/resumableTesting Tips
- โขPOST with Upload-Length opens a session โ read the id from the Location header
- โขHEAD returns the authoritative Upload-Offset; never trust your own byte count after a failure
- โขPATCH with a stale Upload-Offset is rejected with 409 โ re-read the offset and continue from there
- โขExceeding the declared Upload-Length returns 413; DELETE cancels the session
- โขSession state is per-instance and expires after 10 minutes โ a resumed test must tolerate a cold session
// Playwright API Testing - File Operationsimport { test, expect } from '@playwright/test';test('File download', async ({ request }) => {const response = await request.get('/api/files/download/report.pdf');expect(response.ok()).toBeTruthy();expect(response.headers()['content-type']).toContain('application/pdf');const buffer = await response.body();expect(buffer.length).toBeGreaterThan(0);});
Challenge ID: files-resumable-upload
2 frameworks available
API Playground
Send requests and inspect responses
Endpoint: /api/v1/upload/resumable
Press Enter to send