cancel
Showing results for 
Search instead for 
Did you mean: 

CAP + Angular = CORS block on CAP service

JuanjoGersol
Explorer
0 Kudos

Dear Experts,

I'm working on a big project having at the moment 9 applications.

I have 4 fiori elements apps and 3 fiori freestyle applications in the same project, together with the CAP service.

In parallel I have to develop an angular application for public access. I tried to have all together in the same project but it became impossible to me to get a working project able to be built and deployed to cloud foundry.

I have created the angular application in another project. It is a form which uses the CAP service to retrieve the information for value helps.

The oData calls are working fine on a local environment with proxy or using CORS anywhere chrome extension:

  getCountries():Observable<OData> {
    var response = this.http.get<OData>(this.baseUrl+"Countries?$format=json");
    return response;
  }

I'm using the information from this post to configure my deployed CAP service on the mta.yaml file:

#                            CAP
 # --------------------- SERVER MODULE ------------------------
 - name: cockpit-srv
 # ------------------------------------------------------------
   type: nodejs
   path: gen/srv
   requires:
    # Resources extracted from CAP configuration
    - name: cockpit-db
   provides:
    - name: srv-api      # required by consumers of CAP services (e.g. approuter)
      properties:
        srv-url: ${default-url}
   properties:
      CORS:
        - uriPattern: .
          allowedMethods:
            - GET
            - POST
          allowedOrigin:
            - host: '*'

Configuration is saved on the user-provided variables (manually changed after deployment):

[
{
"allowedMethods" : [ "GET", "POST" ],
"allowedOrigin" : [ {
"host" : "*",
"protocol": "https"
} ],
"uriPattern" : "."
} 
]

But when I try to access from the angular application I get CORS error:

So it seems the server is not providing the header: Access-Control-Allow-Origin: *

I have not been able to find any reference on the Capire documentation about CORS so I'm not sure if something else is needed.

Thank you in advance,

Kind regards,

Accepted Solutions (1)

Accepted Solutions (1)

klaus_kopecz
Participant
0 Kudos

Hi Juanjo,

As shown in the post you are referring to, the CORS-configuration in mta.yaml must be part of the approuter module in mta.yaml. CAP (configured via the srv-module) does not know about CORS.

Regards, KK

JuanjoGersol
Explorer
0 Kudos

Hi Klaus,

Thank you for pointing that out! I have been learning all these technologies in the last weeks and it's easy to be lost in small details.

I will try and let you know.

In any case I'm also trying to get working the combined (fiori + angular + cap) project.

Kind regards,

klaus_kopecz
Participant
0 Kudos

Great. Would be perfect if you can then share your results/experiences here ...

JuanjoGersol
Explorer

Dear Klaus,

Thank you very much! I have just reuploaded my whole project, and CORS is granted if the CAP service is exposed through the app router.

For newbies this is really important, as we have the CAP service URL that you can access from everywhere and that provides you with nice oData service, so your first attemp is to use that URL.

I didn't realize of that until I integrate the external app, because for basic projects in which all coding is provided by the generators you don't stop to think how everything works.

Kind regards!

klaus_kopecz
Participant

Hi Juanjo,

Approuter is an important component of a complete application in the Cloud Foundry environment of SAP Cloud Platform. It is the frontend server playing various roles which are nicely described in this blog. Authentication is the most obvious function of the approuter.

KK

gregorw
Active Contributor
0 Kudos

Great that you've got it working. Have you updated also the your example repository?

Cristian
Participant
0 Kudos

jjgersol klaus.kopecz

Hope you are doing well.

I am facing exactly the same issue. We have a React app that is getting failed whilst consuming the CAP based ODATA service due to a CORS issue.

As mentioned by klaus.kopecz , we added the CORS properties in the router module but still facing the same issue.

 # --------------------- APP ROUTER MODULE ------------------------
 - name: integration-suite-tools-router
 # ----------------------------------------------------------------
 type: approuter.nodejs
 path: app-router
 parameters:
 disk-quota: 256M
 memory: 256M
 requires:
 - name: integration-suite-tools-uaa
 - name: srv-api
 group: destinations
 properties:
 name: srv-api
 url: ~{srv-url}
 forwardAuthToken: true
 properties: 
 CORS:
 - uriPattern: .
 allowedMethods:
 - GET
 - POST
 allowedOrigin:
 - host: '*'

In the app router app, I can see the user provided variable created CORS successfully created as follows:

[ {
"allowedMethods" : [ "GET", "POST" ],
"allowedOrigin" : [ {
"host" : "*"
} ],
"uriPattern" : "."
} ]

Any idea about what can be wrong?

Many thanks in advance.

C.

Answers (2)

Answers (2)

gregorw
Active Contributor
0 Kudos

Hi jjgersol,

as it seems you deploy your app to SAP Cloud Platform using MTA. Why don't you simply deploy also the Angular part with this MTA using the Approuter and configure it as the reverse proxy to the CAP srv?

Best regards
Gregor

JuanjoGersol
Explorer
0 Kudos

Hi Gregor!

Thank you, I have tried to integrate the angular app in my "big" project together with the other fiori apps, but I'm not able to make it work, build + pack + deploy. My project is taking 30/40 minutes in build so after 10 tries I lost all the time I could and went to this alternative.

In any case, what I'm trying to do is pretty normal if you want to expose a service for an API. Do you have a clue why it's not working? I have checked every log in the CF/Hana environment but at the moment I don't really now if CORS configuration is being taken into account or not.

gregorw
Active Contributor
0 Kudos

Dear Juanjo,

to be able to help you it would be good if you can describe in bit more detail the architecture of your application. Where is the Angular App hosted? What is used for authentication? Does the Angular App send the JWT directly to the CAP srv?

Regarding your issue with the "big" project I would suggest you create a simple playground project (which you might be also able to share on a public Git repository) get down to quick cycles so you are able to test results quickly.

Best regards
Gregor

JuanjoGersol
Explorer
0 Kudos

Hi gregorw,

First of all thank you for your help.

I have created this sample project:

https://github.com/jofunkillo/cap_fiori_angular

The project contains two services (public/private) and 3 apps, 2 fiori elements (private) and 1 angular (public).

It also contains approuter, deployer and launchpad apps for the fiori elements apps deployment.

It correctly compiles:

Locally all apps run fine:

Local launchpad:

Accounts App:

Centers App:

Angular app works with a local proxy to skip CORS on local development:

Deployment to CF is in error:

The error 1001 is generic and in this case no additional information is provided, sometimes 1001 is related to app size but I tried different configurations without success.

I think the problem is my configuration of the MTA is not zipping the angular application:

I used this wonderful guide to create initial project:

https://blogs.sap.com/2020/09/01/how-to-build-end-to-end-custom-applications-in-cloud-foundry/

I also used tool cf-create-app to generate the project, but the problem is combining cap+fiori with cap+angular into one project.

Finally I think I need a destination for the angular applicaction in the mta.yaml file and that destination should be used in the approuter configuration xs-app.json.

Kind regards,

gregorw
Active Contributor
0 Kudos

I have the following suggestiony to your repository:

  1. Add all generated files to the .gitignore to avoid checking them into the Git repository
  2. I've sent you a pull request to use simply the same path in the Angular app as used also in the SAPUI5 Fiori Elements App. That way the Angular App should also work when deployed and has no other proxy than the approuter that also the Fiori Apps use.
  3. I think you've missed to create the manifest.json as described by in the post How to build End-to-End custom applications in Cloud Foundry by Rafael Lopez Martinez. Please try to add it and hopefully this will avoid the error:

    "Error checking status of content deployment from module "testapp_ui_deployer" in content service "testapp_html5_repo_host": Internal server error occurred during processing of operation 'Get Deploy Resource': Upload application content failed { CODE: '1001' }"

Best regareds
Gregor

JuanjoGersol
Explorer
0 Kudos

Thank you Gregor! I will work on these topics and come back with results.

JuanjoGersol
Explorer
0 Kudos

Dear gregorw,

I worked yesterday on the problem and I was not able to fix the issue. I compared in parallel a totally new angular + cap project with the example from git, and apparently the created artifacts into the MTAR file are equal but I'm still getting 1001 error when deploying. I have removed all apps into my account to issolate whether the reason can be lack of space or memory.

Unfortunately there is no more information about the reason. Is there a way to activate a verbose mode?

JuanjoGersol
Explorer

I probably found the reason of the wrong deployment.

My deployer is com.sap.application.content:

- name: testapp_ui_deployer
   type: com.sap.application.content
   path: deployer
   requires:
     - name: testapp_html5_repo_host

This is fine to deploy portal + fiori apps, but it seems I can't configure properly to also deploy the angular app, it has sense as launchpad applications are usually ui5 fiori apps.

I have seen angular basic projects deploy with com.sap.html5.application-content deployer:

# ----------------------- ANGULAR DEPLOYER ---------------------
  - name: angulapp-hmtl5-deployer
  # --------------------------------------------------------------
    type: com.sap.html5.application-content
    path: html5Deployer
    requires:
      - name: angulapp-html5-host        

So I'm asking if the mta.yaml file can be configure with two deployers.

If I'm lucky I will update the GIT repository for other with the same problem.

yogananda
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi @jjgersol

You can find it in this blog How to fix cors

JuanjoGersol
Explorer
0 Kudos

Hi Yogananda, I went to that article, I understand the only thing I have to do is to return the correct header to avoid the browser to produce the CORS error, but in the scope of a CAP service I have no clue how to implement it.

I'm checking now if in the service implementation I'm able to append the header:

srv.after('READ','Countries', async (regs, req) => {
        //Alter headers here
    })<br>

But I'm not sure if that is even possible.

Thank you very much!

Vlad
Advisor
Advisor
0 Kudos

Hi jjgersol,

for development purposes I use the dirty trick:

this.after("*", async (each, req) => {
    if (req.res) {
        req.res.set("Access-Control-Allow-Origin", "*");
    }
});

Please tell nobody 🙂 It worked well for me:

Vlad
Advisor
Advisor

Well... my previous comment was a bit wrong (I will keep it for historical reasons), because people from CAP has decided to add a so-called request validator that doesn't allow preflight (OPTIONS) requests. However, from the skinny documentation I have identified that you can create a file srv/server.js, and intercept the bootstrapping process, where you can use the cors middleware for express.js.

p.s. if this works well for you, I appreciate your credits to me 🙂

const cds = require('@sap/cds');
const cors = require('cors');

cds.on('bootstrap', (app) => {
    console.debug("Use: cors middleware");
    app.use(cors());
})
module.exports = cds.server;