Skip to main content

Overview

The S3MultipartController provides three HTTP endpoints for managing the multipart upload lifecycle: creating uploads, signing part uploads, and completing uploads. Namespace: MrEduar\S3M\Http\Controllers\S3MultipartController Base Route: Configured in your routes file (typically /s3m)

Endpoints

POST /multipart

Create a new multipart upload session.

Request

bucket
string
Custom S3 bucket name (must have allow_change_bucket enabled in config)
visibility
string
default:"private"
S3 ACL visibility (private, public-read, etc.)
content_type
string
default:"application/octet-stream"
MIME type of the file being uploaded
folder
string
default:"tmp"
Folder path within the bucket (must have allow_change_folder enabled in config)

Response

uuid
string
Unique identifier for this upload session
bucket
string
S3 bucket name
key
string
S3 object key (file path: folder/uuid)
uploadId
string
AWS multipart upload ID (required for subsequent requests)
{
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
  "bucket": "my-bucket",
  "key": "tmp/550e8400-e29b-41d4-a716-446655440000",
  "uploadId": "exampleUploadId123"
}

Events

Dispatches MultipartUploadCreated event with uuid, bucket, key, and uploadId.

Example

const response = await fetch('/s3m/create-multipart-upload', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-TOKEN': csrfToken
  },
  body: JSON.stringify({
    content_type: 'video/mp4',
    folder: 'videos',
    visibility: 'private'
  })
});

const { uuid, bucket, key, uploadId } = await response.json();

POST /multipart/sign

Generate a presigned URL for uploading a specific part of the file.

Request

key
string
required
S3 object key from the create upload response
part_number
integer
required
Part number (starting from 1, max 10,000)
upload_id
string
required
Upload ID from the create upload response
bucket
string
Custom S3 bucket name
visibility
string
S3 ACL visibility
content_type
string
default:"application/octet-stream"
MIME type for this part

Response

bucket
string
S3 bucket name
key
string
S3 object key
url
string
Presigned URL for uploading this part (valid for 5 minutes)
headers
object
HTTP headers to include in the upload request
Content-Type
string
Content type header value
{
  "bucket": "my-bucket",
  "key": "tmp/550e8400-e29b-41d4-a716-446655440000",
  "url": "https://my-bucket.s3.amazonaws.com/tmp/550e8400...?X-Amz-Algorithm=AWS4-HMAC-SHA256&...",
  "headers": {
    "Content-Type": "video/mp4",
    "Host": ["my-bucket.s3.amazonaws.com"]
  }
}

Example

// Get presigned URL for part 1
const signResponse = await fetch('/s3m/create-sign-part', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-TOKEN': csrfToken
  },
  body: JSON.stringify({
    key: key,
    upload_id: uploadId,
    part_number: 1,
    content_type: 'video/mp4'
  })
});

const { url, headers } = await signResponse.json();

// Upload the part using the presigned URL
const uploadResponse = await fetch(url, {
  method: 'PUT',
  headers: headers,
  body: filePart
});

const etag = uploadResponse.headers.get('ETag');
Presigned URLs expire after 5 minutes. You must upload the part within this timeframe.

POST /multipart/complete

Complete the multipart upload by assembling all uploaded parts.

Request

bucket
string
Custom S3 bucket name
key
string
required
S3 object key from the create upload response
upload_id
string
required
Upload ID from the create upload response
parts
array
required
Array of uploaded parts with their ETags
parts[].PartNumber
integer
required
Part number (must match the part_number used when uploading)
parts[].ETag
string
required
ETag value from the part upload response headers

Response

url
string
Public URL of the uploaded file
key
string
S3 object key
{
  "url": "https://my-bucket.s3.amazonaws.com/tmp/550e8400-e29b-41d4-a716-446655440000",
  "key": "tmp/550e8400-e29b-41d4-a716-446655440000"
}

Events

Dispatches MultipartUploadCompleted event with bucket, key, upload_id, and location.

Example

const completeResponse = await fetch('/s3m/complete-multipart-upload', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-TOKEN': csrfToken
  },
  body: JSON.stringify({
    key: key,
    upload_id: uploadId,
    parts: [
      { PartNumber: 1, ETag: '"etag-from-part-1"' },
      { PartNumber: 2, ETag: '"etag-from-part-2"' },
      { PartNumber: 3, ETag: '"etag-from-part-3"' }
    ]
  })
});

const { url, key: uploadedKey } = await completeResponse.json();
console.log('File uploaded to:', url);

Controller Methods

createMultipartUpload()

public function createMultipartUpload(CreateMultipartUploadRequest $request): JsonResponse
See POST /multipart endpoint documentation above. Source: /home/daytona/workspace/source/src/Http/Controllers/S3MultipartController.php:30

signPartUpload()

public function signPartUpload(SignPartRequest $request): JsonResponse
See POST /multipart/sign endpoint documentation above. Source: /home/daytona/workspace/source/src/Http/Controllers/S3MultipartController.php:68

completeMultipartUpload()

public function completeMultipartUpload(CompleteMultipartUploadRequest $request): JsonResponse
See POST /multipart/complete endpoint documentation above. Source: /home/daytona/workspace/source/src/Http/Controllers/S3MultipartController.php:102

Middleware

The controller applies middleware configured in config('s3m.middleware'). By default, this includes authentication and CSRF protection.

Authorization

All endpoints require authorization through the uploadFiles gate, which receives the authenticated user and bucket name.

Build docs developers (and LLMs) love