cancel
Showing results for 
Search instead for 
Did you mean: 

UI5 File Upload via OData Batch Request to Keep Transaction Security?

NabiZamani
Contributor

How can I do a file upload during an OData Batch Request and still maintain proper transaction security? So the goal is to have "all or nothing" saved on the backend, which is typically realized by wrapping the actual requests into a ChangeSet.

We are using SAPUI5/OpenUI5 1.36.8 and SAP GW on NW 7.5 SP02. Furthermore, we are using a Component based app with sap.ui.model.odata.v2.ODataModel and batch requests are enabled.

Let's assume we have an Entity Employee + Photo, as well as the corresponding EntitySets Employees + Photos. Furthermore, we have a navigation Property "Photo" from Employee to Photo (1 to 0..1 Relation) and every employee has a 1 to 1 relation to an Address Entity. In other words, the following is possible:


GET: /Employees('123')                        ==> returns the Employee data, i.e. firstName

GET: /Employees('123')/Photo              ==> returns the Entity data, i.e. uploadedOn

GET: /Employees('123')/Photo/$value  ==> returns the file content, i.e. a jpg file

GET: /Employees('123')/Address          ==> returns the address data, i.e. street,...

Next, let's assume I have an app to add new employees. The app offers several pages/screens to fill the Employee data, the address, and to choose a file. Everything happens on the front end only, until the user presses the save button in the end. Until this happens, no data is sent to the backend. When the save button is pressed "all or nothing" should be saved on the backend. In other words, An Employee Entity is created, an related Address Entity is created, a related Photo Entity is created, and a corresponding File is uploaded. If any of these fails, then the backend should "rollback".

One way to achieve this is creating a deep entity (although deep creates are not supported and may not work). However, how can I make sure that even the file upload via sap.ui.unified.FielUploader is in the same create deep entity request (and ChangeSet) in order to make sure that "all or nothing" is fulfilled?

In fact, sap.ui.model.odata.v2.ODataModel does not support OData Streams, so something like createStream(), deleteStream(), updateStream(), or readStream() is not available in the v2.ODataModel. Creating deep entities together with the file content in one request is also not supported. At the same time the sap.ui.unified.FielUploader always sends POST requests - using a different HTTP METHOD (i.e. PUT) is not possible because it's hard coded. The FileUploader has no special support for the ODataModel and/or OData Streams, it basically only needs the upload URL and that's it.

So my next question is (slightly different then the one from above):

How can I put a CREATE STREAM or UPDATE STREAM (= File Upload via POST or File Upload via PUT) into a batch request containing other changes as well (all in one change set) to achieve the "all or nothing" approach? Of course, this would not work in all browsers because I would have to access the file's binaries...

If this is not possible out of the box (and I'm pretty sure of this) then the workaround is very "hacky" and might include special handling on both front end and backend, right? I want to avoid modifying the UI5 libs, i.e. extending the batch request handling, adding support of PUT to the FileUploader, etc. How do you achieve transaction security in such cases, what are the best practices? Or is there anything I'm missing?

Hint:

To make SAP GW accept a POST (Create) on a Navigation property we have to tweak the relationships on GW, for details see https://scn.sap.com/thread/3592469 and http://scn.sap.com/thread/3580538

Accepted Solutions (0)

Answers (1)

Answers (1)

kenichi_unnai
Advisor
Advisor
0 Kudos

Hi Nabi,

From the SAP Gateway side I guess (haven't done such use cases by myself) all should work.

If the UI5 side supports the file upload via POST as you mentioned, the online/offline store would work too.

Best regards,

Ken

PS. As you are already aware, my H2G should help you to get the idea about navigation links for creating associated entities during $batch request, together with the LUW during the $batch call.

NabiZamani
Contributor
0 Kudos

Hi Kenichi,

Thank you for your help! Indeed, as you know I have read your articles and I really enjoyed them 🙂

I also assume that this should work from GW point of view. However, the UI5 side seems not to offer the required features for adding a file upload to a change set in a batch request for achieving "all or nothing". That's why I have put this question into the SAPUI5 discussion group...

The SAPUI5 FileUploader actually only supports POST. However, as far as I can see file upload offline scenarios via $batch (the scenarios you described in your article) are absolutely not supported by SAPUI5 out of the box. That means some probably not easy custom code is needed, which would add the needed functionalities to the ODataModel. Also, In order to add a file to a change set in a $batch the file content (binaries) must be retrieved. Keep in mind that this stuff would not work across all browsers, so browser compatibility is another challenge (see FileAPI and FileReader API).

By the way - everyone if welcome to correct me if I'm wrong...

Best, Nabi

kenichi_unnai
Advisor
Advisor
0 Kudos

Ok, now I got the problem.

Are you trying to access your SAP Gateway services directly from the UI5 based code - or via HCPms/SMP3?

NabiZamani
Contributor
0 Kudos

I can easily use the SAPUI5 FileUploader to upload a File to my GW service (create_stream...), so that would work just fine - I've done that many times in the past. However, now I'm wondering how to put the file into a change set and then trigger the upload from SAPUI5 via $batch. So I'm trying to access the GW service directly form SAPUI5. I assume SAPUI5 does not offer me much to do this, although I guess it should work just fine from GW side...

kenichi_unnai
Advisor
Advisor
0 Kudos

Alright perhaps you would need to experiment a bit further but here's a hint from Kapsel colleagues - you could apply to your own use cases with UI5:

As you know batch media is supported, but there is no specific Kapsel API for this. It is up to UI5, datajs, or whatever JavaScript library is being used to create the batch request.

You would likely need to use the FileReader API to convert the File object to raw binary or base64 when creating the request.

There was a testing of the FileReader to convert to base64 and passed it through datajs to create the batch request.  Note that request.body needs to be used instead of request.data with datajs to prevent the request handlers from trying to convert the data as it only supports JSON, XML, and text.

NabiZamani
Contributor
0 Kudos

Thanks, Kenichi!

That's the worst thing I expected: starting to create own $batch requests + making sure that this works hand in hand with the $batch requests created by sap.ui.model.odata.v2.ODataModel in SAPUI5. In fact, like I mentioned above, I would prefer not to extend the sap.ui.model.odata.v2.ODataModel so that $batch file uploads are supported. Anyway, I think there is no other way as of today.

kenichi_unnai
Advisor
Advisor
0 Kudos

FYI this is the reference of $batch via kapsel:

NabiZamani
Contributor
0 Kudos

Thanks, Kenichi! You are so passionate 🙂

TimMuchena
Participant
0 Kudos

Hi

Did you manage to find a solution for incorporating file upload into a batch request? If so do you mind sharing your code. I have a same requirement and i am stuck.

Thank you

NabiZamani
Contributor
0 Kudos

Timothy,

I'm afraid to tell you that I this is currently not supported by SAPUI5 out of the box. Anyone can correct me if I'm wrong. I did not work on this anymore...

FYI - there is a feature request on Github related to Content-ID. There I mentioned that I would love to see file uploads working with it as well. Let's see what happens...

Best, Nabi