Skip to content

Stream Properties

traverse supports reading and writing OData stream properties - binary content attached to an entity, such as profile photos, document files, or thumbnails.

Reading a stream property

import (
    "io"
    "os"
    "github.com/jhonsferg/traverse"
)

client := traverse.New(traverse.Config{BaseURL: "https://api.example.com/odata"})

// GET /Products(1)/Photo
reader, contentType, err := client.Entity("Products", 1).
    StreamProperty("Photo").
    Download(ctx)
if err != nil {
    log.Fatal(err)
}
defer reader.Close()

log.Printf("content type: %s", contentType)
io.Copy(os.Stdout, reader)

Writing a stream property

f, err := os.Open("photo.jpg")
if err != nil {
    log.Fatal(err)
}
defer f.Close()

// PUT /Products(1)/Photo
err = client.Entity("Products", 1).
    StreamProperty("Photo").
    Upload(ctx, f, "image/jpeg")
if err != nil {
    log.Fatal(err)
}

Deleting a stream property

// DELETE /Products(1)/Photo
err := client.Entity("Products", 1).
    StreamProperty("Photo").
    Delete(ctx)

Multipart upload

For large files, use chunked multipart upload:

err := client.Entity("Documents", docID).
    StreamProperty("Content").
    UploadMultipart(ctx, traverse.MultipartOptions{
        Reader:      file,
        ContentType: "application/pdf",
        ChunkSize:   4 * 1024 * 1024, // 4 MB chunks
        OnProgress: func(uploaded, total int64) {
            log.Printf("uploaded %d/%d bytes", uploaded, total)
        },
    })

Stream URL

Get the URL for a stream property without downloading:

url, err := client.Entity("Products", 1).
    StreamProperty("Photo").
    URL(ctx)
// url = "https://api.example.com/odata/Products(1)/Photo"

See also