cancel
Showing results for 
Search instead for 
Did you mean: 

SAP CAP - How to create an action for uploading files

sub_han
Advisor
Advisor
7,100

Hi,

I am trying to implement an endpoint that allows me to upload files from the browser.
Here is a sample fetch request from the client(browser)

const files =event.getParameter('files');
const file= files[0];
const formData =new FormData();
formData.append(file.name,file);
fetch({
  url:`/item/upload`,
  method:'POST',
  body: formData,
})

How do I implement this action in my .cds file.
It looks like this right now (simplified)

service ItemService {

type statusMessageType {
  ok      : Boolean;
  message:String;
  status: Integer;
  ID:String;
};
  action importEnvironment(fileId :String, envId :String, ver :String) returns statusMessageType;
  action deleteItem(ID:String) returns statusMessageType;
  action addFolder(folderName :String, currentFolderID :String) returns statusMessageType;
  action renameItem(sourceID :String, targetID :String) returns statusMessageType;
  
  action upload() returns statusMessageType;

}

How do I 'catch' the `formData` (body) in this `upload()` action as a parameter? And what type should it have? Binary?

Is this possible?

As a workaround I have implemented it as a normal express endpoint and it works in development.

But when I deploy my app to cloud foundry all my express implemented endpoints such as the following are not found and I get a 404 for them.

app.post('/upload');
app.get('/getItems');

Is this expected since we are not 'supposed' to do it like this?

Accepted Solutions (0)

Answers (2)

Answers (2)

gregorw
SAP Mentor
SAP Mentor

Please check out the example CAP Media Handling or the one in cloud-cap-samples

sub_han
Advisor
Advisor
0 Kudos

Yes I did initially.
But I don't want the file to be saved in the db.
In fact, I am not planning on using a db at all.
I want to just save the file to amazon s3.

For s3 examples, I also checked https://github.com/pdominique/cap-media-node .

But even here I first need to send a POST request (which adds an entry to the db) and then I have to send a PUT request to actually 'upload' the file to s3.
I don't wish to send a POST request first as I don't want to have a db at all.

Is this possible?
Just one POST request with the body containing the file so I can upload it to s3 ?

gregorw
SAP Mentor
SAP Mentor
0 Kudos

What's the issue with the two requests? And how do you want to find the document stored in S3 without having a reference in your database?

sub_han
Advisor
Advisor
0 Kudos

I find the s3 object by id.
I am using the 'aws-sdk' package.

To get all the objects i simply use s3.listObjects()

And to get a particular object(in this case a file), i simply generate a signed URL with s3.getSignedUrl().

Getting the objects from s3 is perfectly working and not a problem. And for this I really don't need any reference in a db.

I don't have any problem with 2 requests. My only question is if there is a way to send files from browser to the cds backend without saving a reference in the db first? I just want to get the file and send it to s3...

gregorw
SAP Mentor
SAP Mentor

If you want to follow the OData standard: No.

You can still implement your custom handlers in express.

pierre_dominique2
Contributor

If you want to implement a custom express handler, here's an example: https://github.com/SAP-samples/hana-opensap-cloud-2020/blob/main/srv/routes/excel.js

This video might help -> https://youtu.be/dmeRX9n6uQo

shravan_pishike
Explorer
0 Kudos

Hi @gregorw ,

I'm trying to have an upload action in my cds. Trying something like this 

action   uploadExcelFile(file : LargeBinary @Core.MediaType: 'text/csv');

 and defined a handler in the service layer (JAVA). But whenever I try to hit this action using postman, I get the below error

{
    "error": {
        "code": "70005",
        "message": "The content type 'text/csv' is not supported."
    }
}
Any idea on how to solve this?
danilo_apicella1
Explorer
0 Kudos

Taking your example as a reference, the upload action would need to have a parameter defined as type Binary or LargeBinary. Then, you would need a custom event handler for the action (https://cap.cloud.sap/docs/guides/providing-services#custom-event-handlers). The file would be accessible to you through the req argument of the handler, as one of its parameters (https://cap.cloud.sap/docs/node.js/events#params).

So a hypothetical custom event handler for your action "upload" with argument "file" of type LargeBinary would look like this:

 

this.on ('upload', (req)=>{
  const file = req.params.file;
  //file upload to s3
})

 

shravan_pishike
Explorer
0 Kudos

@danilo_apicella1 I do have the custom handler written in my code. But it is not triggered on the post call, I get the error before that itself.

I'm using CAP Java.

Swetha__Balusamy
Explorer
0 Kudos
I am also facing the same issue. Please let me know if you have found the solution