Serving Media Data
CAP provides out-of-the-box support for serving media and other binary data. Media data can be stored either directly in the database or in an external repository, and can be streamed to and from clients. CAP uses OData V4's support for media resources to handle media 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.MediaTypeannotation 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.Filenameis specified, by setting toinline(see the fifth example). If omitted, the behavior is@Core.ContentDisposition.Type: 'attachment'.
Learn more how to enable stream support in SAP Fiori elements.
The following examples show these annotations in action:
- Media data is stored in a database with a fixed media type
image/png:
entity Books { //...
image : LargeBinary @Core.MediaType: 'image/png';
}- Media data is stored in a database with a variable media type:
entity Books { //...
image : LargeBinary @Core.MediaType: imageType;
imageType : String @Core.IsMediaType;
}- Media data is stored in an external repository:
entity Books { //...
imageUrl : String @Core.IsURL @Core.MediaType: imageType;
imageType : String @Core.IsMediaType;
}- Content disposition data is stored in a database with a variable disposition:
entity Authors { //...
image : LargeBinary @Core.MediaType: imageType @Core.ContentDisposition.Filename: fileName;
fileName : String;
}- The image shall have the suggested file name but be displayed inline nevertheless:
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:
GET ../Books(201)/image
> Content-Type: application/octet-streamThe response's
Content-Typeheader is typicallyapplication/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.IsMediaTypecontent.
Read media data with @Core.ContentDisposition.Filename in the model:
GET ../Authors(201)/image
> Content-Disposition: 'attachment; filename="foo.jpg"'The media data is streamed automatically.
Learn more about returning a custom streaming object (Node.js - beta).
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:
POST ../Books
Content-Type: application/json
{ <JSON> }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:
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:
DELETE ../Books(201)Alternatively, you can delete a media data element individually:
DELETE ../Books(201)/imageUsing 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.
GET: ../Books(201)
>{ ...
image@odata.mediaReadLink: "http://other-server/image.jpeg",
image@odata.mediaContentType: "image/jpeg",
imageType: "image/jpeg"
}Conventions & 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:
GET $filter=ID eq binary'Q0FQIE5vZGUuanM='Node.js Runtime Conventions and Limitations
- The usage of binary data in some advanced constructs like the
$applyquery 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.
- Please note, that SQLite doesn't support streaming. That means, that LargeBinary fields are read as a whole (not in chunks) and stored in memory, which can impact performance.
- 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.hana.base64_to_buffer: false.