Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serverless Web App Architecture

I am currently designing a simple Serverless Web App using Serverless.

My current expected stack is;

  • API Gateway
  • Lambda
  • DynamoDB
  • Static Single Page App

I have followed a few tutorials for building the Serverless API, Lambda and DynamoDB using the Serverless Framework and I have built my single page app however right now they are 2 separate entities.

What I am looking to do now is bring the static site (nodejs) into the same project as my API, Lambda and DynamoDB and use the Serverless Framework to control the deployment however I'm struggling to find guidance on;

  1. How do you represent the static web site part in the Serverless Framework
  2. How best to host that static web site (e.g. s3 static site hosting or other option?)
  3. How best to reference a API Gateway URL that is being generated at the same time the deployment is happening (e.g. via Serverless Framework)

Could anyone provide any insight into how this is supposed to work, or maybe point me int he direction of some good blogs/resources?

Kind Regards, John

like image 996
John Bartlett Avatar asked Jan 17 '18 15:01

John Bartlett


2 Answers

I had a SPA (single page application) written in React communicating to a REST JSON API written in nodejs and hosted on Heroku as a monolith. I migrated to AWS Lambda and split the monolith into 3+ AWS Lambdas micro services inside of a monorepo The following project structure is good if your SPA requires users to login to be able to do anything. I used a single git repository where I have a folder for each service:

  • api
  • app
  • www

Inside of each of the services' folders I have a serverless.yml defining the deployment to a separate AWS Lambda. Each service maps to only 1 function index which accepts all HTTP endpoints. I do use 2 environments staging and production. My AWS Lambdas are named like this:

  • example-api-staging-index
  • example-api-production-index
  • example-app-staging-index
  • example-app-production-index
  • example-www-staging-index
  • example-www-production-index

I use AWS Api Gateway's Custom Domain Names to map each lambda to a public domain:

  • api.example.com (REST JSON API)
  • app.example.com (single page application that requires login)
  • www.example.com (server side rendered landing pages)

  • api-staging.example.com

  • app-staging.example.com
  • www-staging.example.com

You can define the domain mapping using serverless.yml Resources or a plugin but you have to do this only once so I did manually from the AWS website console. My .com domain was hosted on GoDaddy but I migrated it to AWS Route 53 since HTTPS certificates are free.

app service

  • /bundles-production
  • /bundles-staging
  • src (React/Angular single page application here)
  • handler.js
  • package.json
  • serverless.yml

The app service contains a folder /src with the single page application code. The SPA is built locally on my computer in either ./bundles-production or ./bundles-staging based on the environment. The built generates the .js and .css bundles and also the index.html. The content of the folder is deployed to a S3 bucket using the serverless-s3-deploy plugin when I run serverless deploy -v -s production. I defined only 1 function getting called for all endpoints in the serverless.yml (I use JSON instead of YAML):

...
    "functions": {

        "index": {
            "handler": "handler.index",
            "events": [
                { "http": "GET /" },
                { "http": "GET /{proxy+}"}
            ]
        },

    },

The handler.js file returns the index.html defined in /bundles-staging or /bundles-production

I use webpack to build the SPA since it integrates very well with serverless with the serverless-webpack plugin.

api service I used aws-serverless-express to define all the REST JSON API endpoints. aws-serverless-express is like normal express but you can't do some things like express.static() and fs.sendFile(). I tried initially to use a separate AWS Lambda function instead of aws-serverless-express for each endpoint but I quickly hit the CloudFormation mappings limit.

www service If most of the functionality of your single page application require a login it's better to place the SPA on a separate domain and use the www domain for server-side rendered landing pages optimized for SEO.

BONUS:

graphql service Using a micro service architecture makes it easy to experiment. I'm currently rewriting the REST JSON API in graphql using apollo-server-lambda

like image 127
Giorgio Avatar answered Oct 06 '22 16:10

Giorgio


I have done pretty much the same architecture and hosted the single page app on s3. What you can do is set up cloudfront for api gateway and than point api.yourDomain.com to that cloudfront. Than you will also need to enable cors on your api.

This plugin handles setting up domain and cloudfront for you:

https://github.com/amplify-education/serverless-domain-manager

I am not sure about your project requirements but if you want to serve static files faster setting up domain->cloudfront->s3 might be a wise choice.

like image 20
Vjerci Avatar answered Oct 06 '22 15:10

Vjerci