Skip to content
On this page

Serving Media Data

CAP provides out-of-the-box support for serving media and other binary data.

Annotating Media Elements

You can use the following annotations in the service model to indicate that an element in an entity contains media data.

@Core.MediaType : Indicates that the element contains media data (directly or using a redirect). The value of this annotation is either a string with the contained MIME type (as shown in the first example), or is a path to the element that contains the MIME type (as shown in the second example).

@Core.IsMediaType : Indicates that the element contains a MIME type. The @Core.MediaType annotation of another element can reference this element.

@Core.IsURL @Core.MediaType : Indicates that the element contains a URL pointing to the media data (redirect scenario).

@Core.ContentDisposition.Filename : Indicates that the element is expected to be displayed as an attachment, that is downloaded and saved locally. The value of this annotation is a path to the element that contains the Filename (as shown in the fourth example ).

@Core.ContentDisposition.Type : Can be used to instruct the browser to display the element inline, even if @Core.ContentDisposition.Filename is specified, by setting to inline (see the fifth example). If omitted, the behavior is @Core.ContentDisposition.Type: 'attachment'.

WARNING

@Core.ContentDisposition.Type is currently only available for the Node.js runtime.

The following examples show these annotations in action:

  1. Media data is stored in a database with a fixed media type image/png:
cds
entity Books { //...
  image : LargeBinary @Core.MediaType: 'image/png';
}
entity Books { //...
  image : LargeBinary @Core.MediaType: 'image/png';
}
  1. Media data is stored in a database with a variable media type:
cds
entity Books { //...
  image : LargeBinary @Core.MediaType: imageType;
  imageType : String  @Core.IsMediaType;
}
entity Books { //...
  image : LargeBinary @Core.MediaType: imageType;
  imageType : String  @Core.IsMediaType;
}
  1. Media data is stored in an external repository:
cds
entity Books { //...
  imageUrl  : String @Core.IsURL @Core.MediaType: imageType;
  imageType : String @Core.IsMediaType;
}
entity Books { //...
  imageUrl  : String @Core.IsURL @Core.MediaType: imageType;
  imageType : String @Core.IsMediaType;
}
  1. Content disposition data is stored in a database with a variable disposition:
cds
entity Authors { //...
  image : LargeBinary @Core.MediaType: imageType @Core.ContentDisposition.Filename: fileName;
  fileName : String;
}
entity Authors { //...
  image : LargeBinary @Core.MediaType: imageType @Core.ContentDisposition.Filename: fileName;
  fileName : String;
}
  1. The image shall have the suggested file name but be displayed inline nevertheless:
cds
entity Authors { //...
  image : LargeBinary @Core.MediaType: imageType @Core.ContentDisposition.Filename: fileName @Core.ContentDisposition.Type: 'inline';
  fileName : String;
}
entity Authors { //...
  image : LargeBinary @Core.MediaType: imageType @Core.ContentDisposition.Filename: fileName @Core.ContentDisposition.Type: 'inline';
  fileName : String;
}

Learn more about the syntax of annotations.

WARNING

In case you rename the properties holding the media type or content disposition information in a projection, you need to update the annotation's value as well.

Reading Media Resources

Read media data using GET requests of the form /Entity(<ID>)/mediaProperty:

cds
GET ../Books(201)/image
> Content-Type: application/octet-stream
GET ../Books(201)/image
> Content-Type: application/octet-stream

The response's Content-Type header is typically application/octet-stream.

Although allowed by RFC 2231, Node.js does not support line breaks in HTTP headers. Hence, make sure you remove any line breaks from your @Core.IsMediaType content.

Read media data with @Core.ContentDisposition.Filename in the model:

cds
GET ../Authors(201)/image
> Content-Disposition: 'attachment; filename="foo.jpg"'
GET ../Authors(201)/image
> Content-Disposition: 'attachment; filename="foo.jpg"'

The media data is streamed automatically.

Creating a Media Resource

As a first step, create an entity without media data using a POST request to the entity. After creating the entity, you can insert a media property using the PUT method. The MIME type is passed in the Content-Type header. Here are some sample requests:

cds
POST ../Books
Content-Type: application/json
{ <JSON> }
POST ../Books
Content-Type: application/json
{ <JSON> }
cds
PUT ../Books(201)/image
Content-Type: image/png
<MEDIA>
PUT ../Books(201)/image
Content-Type: image/png
<MEDIA>

The media data is streamed automatically.

Updating Media Resources

The media data for an entity can be updated using the PUT method:

cds
PUT ../Books(201)/image
Content-Type: image/png
<MEDIA>
PUT ../Books(201)/image
Content-Type: image/png
<MEDIA>

The media data is streamed automatically.

Deleting Media Resources

One option is to delete the complete entity, including all media data:

cds
DELETE ../Books(201)
DELETE ../Books(201)

Alternatively, you can delete a media data element individually:

cds
DELETE ../Books(201)/image
DELETE ../Books(201)/image

Using External Resources

The following are requests and responses for the entity containing redirected media data from the third example, "Media data is stored in an external repository".

This format is used by OData-Version: 4.0. To be changed in OData-Version: 4.01.

cds
GET: ../Books(201)
>{ ...
    image@odata.mediaReadLink: "http://other-server/image.jpeg",
    image@odata.mediaContentType: "image/jpeg",
    imageType: "image/jpeg"
}
GET: ../Books(201)
>{ ...
    image@odata.mediaReadLink: "http://other-server/image.jpeg",
    image@odata.mediaContentType: "image/jpeg",
    imageType: "image/jpeg"
}

Serving Binary Data in OData Services — Conventions and Limitations

General Conventions

  • Binary data in payloads must be a Base64 encoded string.
  • Binary data in URLs must have the format binary'<url-safe base64 encoded>'. For example:
http
GET $filter=ID eq binary'Q0FQIE5vZGUuanM='
GET $filter=ID eq binary'Q0FQIE5vZGUuanM='

Node.js Runtime Conventions and Limitations

  • The usage of binary data in some advanced constructs like the $apply query option and /any() might be limited.
  • On SQLite, binary strings are stored as plain strings, whereas a buffer is stored as binary data. As a result, if in a CDS query, a binary string is used to query data stored as binary, this wouldn't work.
  • SAP HANA Database Client for Node.js (HDB) and SAP HANA Client for Node.js (@sap/hana-client) packages handle binary data differently. For example, HDB automatically converts binary strings into binary data, whereas SAP HANA Client doesn't.
  • In the Node.js Runtime, all binary strings are converted into binary data according to SAP HANA property types. To disable this default behavior, you can set the environment variable cds.env.hana.base64_to_buffer to false.