Front-End Web & Mobile

Resolve Single Page Application integration issues with legacy API’s that do not support CORS using AWS

Many modern cloud native web application architectures include Single Page Applications (SPA’s) integrating with multiple backend API’s.

As customers start defining their transitional architectures for modernizing their monolithic web applications and migrating to cloud, one of the common issues that they run into is integrating their modern frontend layer with legacy backend API’s that are running on-premises and/or external service provider running on a different domain.

Traditionally, these legacy API’s are shared by multiple consumers and have limited flexibility to accommodate any changes and/or built using legacy frameworks and technologies that do not support Cross Origin Resource Sharing (CORS).

In this post, we’ll look at leveraging AWS services like Amazon CloudFront, AWS Amplify, Amazon API Gateway, and AWS AppSync to resolve Single Page Applications (SPA’s) integration issues with legacy API’s that do not support Cross Origin Resource Sharing (CORS) as well as leveraging these services to decouple your application architecture and continue to consume your legacy backend API’s.

As shown in Figure 1 below, the SPA frontend app hosted on domain demo-spa-app.com won’t be able to communicate to the legacy backend hosted on demo-legacy-api.io due to CORS security controls with modern browsers. The inability to modify these legacy API’s limits your ability to decouple your frontend from backend API’s and define a path for cloud migration.

Cross Origin Resource Sharing (CORS) is a HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources” from https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS.

Single Page Application (SPA) integration issues with legacy backend API's that do not support Cross Origin Resource Sharing (CORS) and prevent you from modernizing your application architecture.

Figure 1: SPA architecture with legacy API’s with no CORS support.

CloudFront as a reverse proxy

Leveraging Amazon Simple Storage Service (Amazon S3) to host your frontend content and serve and protect it through CloudFront gives you the flexibility to progressively migrate your frontend to scale effortlessly and migrate to serverless architectures. This includes the ability to continue to leverage your existing legacy backend API’s as well as deliver content securely with low latency to users dispersed globally.

Single Page Application (SPA) integration issues with legacy backend API's that do not support Cross Origin Resource Sharing (CORS).

In the Figure 2 above, all requests to the application will be routed to the SPA served through CloudFront hosted at domain demo-spa-app.com. The CloudFront default behavior of * will route all requests to S3 secured through origin access identities (OAI), and any requests that match the path pattern of api/* will be routed to the origin of legacy API at demo-legacy-api.io.

Leverage Amazon Simple Storage Service (Amazon S3) to store SPA frontend content and use Amazon CloudFront as a reverse proxy to route requests to the legacy backend API.

Figure 3: Create CloudFront origins for the frontend and backend layers.

Configure CloudFront Behaviors for the frontend and backend layers. The CloudFront default behavior of * will route all requests to S3 secured through origin access identities (OAI), and any requests that match the path pattern of api/* will be routed to the origin of legacy backend API.

Figure 4: Configure CloudFront behaviors.

Amplify with custom rewrites and redirects

Amplify provides the ability to host your frontend on Amazon S3 and serve and protect it through CloudFront. Amplify also gives you the flexibility to seamlessly integrate with AWS services and adds on features like authentication, storage using reusable components, along with support for automated deployments and hosting.

Leverage Amplify to host your frontend on Amazon S3 and serve and protect it through CloudFront and use custom redirects and rewrite to route to your legacy backend API requests.

Figure 5: Leverage AWS Amplify with custom rewrites and redirects.

In the Figure 5 above, all of the requests to the application will be routed to the SPA served through Amplify hosted at demo-spa-app.com. The Amplify default behavior will route all of the requests to Amplify and any requests that match the path pattern of /api/<*> will be routed to the origin of legacy API at demo-legacy-api.io.

The following rewrite assumes that the context for different endpoints is advertised under the API namespace for https://demo-legacy-api.io/api/ and the SPA custom domain is configured as demo-spa-app.com

Amplify provides the ability to configure the rewrites and redirect requests for any requests that match the path pattern of /api/<*> to route to the legacy backend API.

Figure 6: Configure rewrite for the API requests from SPA to your legacy API.

API Gateway along with AWS Lambda as a proxy

Assuming you now have your SPA frontend content hosted on S3 and served through CloudFront, you can use API Gateway a fully managed service to build your API foundation for your backend API’s and act as front door for applications to access data and business logic using both new and old backend API’s.

In order to address CORS limitation we can use API Gateway along with AWS Lambda as a proxy to integrate to your legacy backend API. API Gateway, a fully managed service to build your API foundation for your backend API’s and act as front door for applications to access data and business logic using both new and old backend API’s.

Figure 7: Leverage API Gateway along with AWS Lambda as a proxy.

In the Figure 7 above, all of the requests to the application will be routed to the SPA served through CloudFront hosted at demo-spa-app.com. SPA API requests will be routed to the API Gateway hosted at subdomain api.demo-spa-app.com. API Gateway will proxy the requests to an AWS Lambda  and the Lambda will make the requests to the demo-legacy-api.io and respond with appropriate CORS response headers.

To leverage API Gateway as proxy for your legacy API, you must first create a Lambda to integrate with your legacy API and respond with appropriate CORS headers, as shown in the following.

AWS Lambda code sample demonstrating the addition of 'Access-Control-Allow-Origin: *' response headers to allow CORS on the response.

Figure 8: Sample AWS Lambda code demonstrating legacy API call and addition of response headers.

Once you have the Lambda in place, you must create an API in API Gateway and setup Lambda proxy integrations. The example is as follows.

Configure API Gateway resource method request to integrate with the Lambda Proxy.

Figure 9: Configure API resource method Integration with AWS Lambda.

Now that you have the API in place, you’ll create a custom domain, i.e., api.demo-spa-app.com, and map the custom domain to the API and complete the API mappings.

Create a custom sub domain for the api and complete the API mappings

Figure 10: Create a custom sub-domain for your API Gateway.

Following the steps above, you now have an API setup in API Gateway that not only can proxy the requests to the legacy API, but also you now have access to a fully managed service where you can create RESTful and WebSocket APIs that will act as a front door for applications to access data and business logic for all of your backend services API’s for all types of applications.

AWS AppSync as a proxy

Assuming you now have your SPA frontend content hosted on S3 and served through CloudFront, you can use AWS AppSync a fully-managed service to build your API with a single GraphQL endpoint that can help with aggregating data from legacy backend API’s, as well as help you build your API foundation for integrating with cloud native microservices deployed in AWS.

AWS AppSync will enable application clients to fetch and post required data in a single request. This will improve the overall efficiency, security posture and performance, as well as reduce costs due to limiting the number of requests and data elements being exchanged.

In order to address CORS limitation we can also use AWS AppSync as a proxy to integrate to your legacy backend API. AWS AppSync helps you leverage a fully-managed service to build your API with a single GraphQL endpoint that can help with aggregating data from legacy backend API’s.

Figure 11: Leverage AWS AppSync as a proxy.

In the Figure 11 above, all of the requests to the application will be routed to the SPA served through CloudFront hosted at demo-spa-app.com. SPA API requests will be to the API Gateway hosted at subdomain api.demo-spa-app.com that will proxy the requests through AWS AppSync to the demo-legacy-api.io API.

To setup a GraphQL API using AWS AppSync, you design a schema and associate data sources to attributes using resolvers. Once you have the AWS AppSync API created, associate your HTTP endpoint data source as shown in the following.

To setup a GraphQL API using AWS AppSync, you design a schema and associate data sources to attributes using resolvers. Once you have the AWS AppSync API created, associate your legacy HTTP endpoint as a data source.

Figure 12: Add legacy API HTTP endpoint as a data source.

Now that you have your data source configured, design your GraphQL schema, and then attach the data source to your schema attribute(s) as shown in the following image. Note that GraphQL schema also lets you attach multiple data source to different attributes of the same schema and acts as a single point of entry for orchestrating across multiple backends.

Now that you have your data source configured, design your GraphQL schema, and then attach the data source to your schema attribute(s). Note that GraphQL schema also lets you attach multiple data source to different attributes of the same schema and acts as a single point of entry for orchestrating across multiple backends.

Figure 13: Configure your HTTP endpoint data sources as a resolver for your data attribute.

Configure your request mapping template to your resource path on the backend API to map the schema attributes as shown in the following.

Configure your request mapping template to your resource path on the legacy backend API and map the schema attributes.

Figure 14: Configure resource mapping template to map the schema attributes.

Finally, create your custom domain, i.e., api.demo-spa-app.com leveraging an existing ACM certificate, and you now have an AWS AppSync API integrated to your legacy API.

Finally, create your custom domain, i.e., api.demo-spa-app.com leveraging an existing ACM certificate, and you now have an AWS AppSync API integrated to your legacy backend API.

Figure 15: Create a custom sub-domain for your AppSync API.

Following the steps above, you now have a GraphQL API setup leveraging AWS AppSync that can not only interact with your legacy API, but also securely interact with data sources in AWS, such as Amazon DynamoDB, Lambda, and more.

Summary

Decoupled frontend and backend architectures provide several benefits, with the core being the separation of concerns and other benefits that include the independent software development lifecycle, development using different languages and frameworks, and continued reuse of the backend API’s.

In this post, we looked at leveraging AWS services like Amazon CloudFront, AWS Amplify, Amazon API Gateway, and AWS AppSync to address SPA integration issues with legacy API’s that do not support CORS. Furthermore, we leveraged these services to decouple your application architecture and integrate with your legacy backend API’s.

About the author:

Nand Venegalla

Nand Venegalla is a Senior Solutions Architect at Amazon Web Services. He has more than 20 years experience in application architecture, development and modernization and is passionate about helping customers migrate applications to Cloud leveraging Agile methodologies and DevOps practices.