diff --git a/README.md b/README.md index 5bff4e6..5cb2e77 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ To be published by Packt Publishing spring 2018 These projects were bootstrapped using the Very Serverless Cookiecutter template. This is a opinionated setup in order to facilitate developing, running and bootstrapping Serverless projects -authored in Python. +authored in mainly in Python. For more information, see the following: diff --git a/ch2/Makefile b/ch2/Makefile index 2a1e7d1..1b8f103 100644 --- a/ch2/Makefile +++ b/ch2/Makefile @@ -1,47 +1,27 @@ -NAME = "verypossible/serverless:1.20.0-python3" - ENVDIR=envs LIBS_DIR=serverless/lib +shell : db + docker-compose run --rm serverless bash +.PHONY: shell -run = docker run --rm -it \ - -v `pwd`:/code \ - --env ENV=$(ENV) \ - --env-file envs/$2 \ - --link=cupping-$(ENV)-postgres \ - --name=coffee-cupping-$(ENV) $(NAME) $1 - -exec_bash = docker exec -it \ - coffee-cupping-$(ENV) bash +db : + docker-compose up -d db +.PHONY: db -shell : check-env env-dir - $(call run,bash,$(ENV)) -.PHONY: shell -attach : check-env +attach : $(call exec_bash,$(ENV)) .PHONY: attach -postgres : check-env - docker run -d -p 5432:5432 --name cupping-$(ENV)-postgres postgres - -start-db : check-env - docker start $(shell docker ps -a | grep cupping-$(ENV)-postgres | awk '{print $$1}') - -stop-db : check-env - docker stop $(shell docker ps | grep cupping-$(ENV)-postgres | awk '{print $$1}') -.PHONY: postgres, start-db, stop-db - -env-dir : - @test -d $(ENVDIR) || mkdir -p $(ENVDIR) -.PHONY: env-dir clean : @test -d $(LIBS_DIR) || mkdir -p $(LIBS_DIR) rm -rf $(LIBS_DIR)/* .PHONY: clean + # make libs should be run from inside the container libs : @test -d $(LIBS_DIR) || mkdir -p $(LIBS_DIR) @@ -59,7 +39,7 @@ libs : # To deploy a single function: make deploy function=FunctionName, where # FunctionName is the named function in your serverless.yml file # -deploy : check-env +deploy : ifeq ($(strip $(function)),) cd serverless && sls deploy -s $(ENV) else @@ -67,12 +47,7 @@ else endif .PHONY: deploy -tests : check-env + +tests : py.test --cov=serverless/ --cov-report=html tests/ .PHONY: tests - - -check-env: -ifndef ENV - $(error ENV is undefined) -endif diff --git a/ch2/README.md b/ch2/README.md index ff26c14..149a348 100644 --- a/ch2/README.md +++ b/ch2/README.md @@ -1,7 +1,129 @@ # Serverless REST API This is an example project of a serverless REST API using the Serverless Framework. This project -corresponds to Chapter 2 of [Serverless Design Patterns and Best -Practices](https://www.packtpub.com/application-development/serverless-design-patterns-and-best-practices) +corresponds to Chapter 2 of +[Serverless Design Patterns and Best Practices](https://www.packtpub.com/application-development/serverless-design-patterns-and-best-practices) [![CircleCI](https://circleci.com/gh/brianz/serverless-design-patterns.svg?style=svg)](https://circleci.com/gh/brianz/serverless-design-patterns) + +# Quickstart for API backend + +*Note*: the quickstart will not work until you've set up the environment. See *Setting up +environment* below + +- Create an environment file in the `envs` directory +- Start up the container +- Install requirements +- Run tests +- Deploy code + +```bash +$ mkdir envs && touch envs/dev +$ ENV=dev make shell +root@72370b69f644:/code# +root@72370b69f644:/code# make libs +root@72370b69f644:/code# make tests +root@72370b69f644:/code# make deploy +``` + +# Setting up environment + +Your environment file needs to have the following key with values. + +``` +AWS_REGION=us-west-2 +AWS_SECRET_ACCESS_KEY= +AWS_ACCESS_KEY_ID= + +VPC_ID= +SUBNET_ID_A= +SUBNET_ID_B= +SUBNET_ID_C= + +CUPPING_DB_USERNAME=root +CUPPING_DB_PASSWORD=asfasfsad3123aa +CUPPING_DB_NAME=cupping_log +``` + +It's easiest to use your `VPC_ID` and `SUBNET_ID` value from your default VPC. Make +sure you set the `AWS_REGION` to whatever region you'll be using. + +To get your default VPC and Subnets: + +- go to https://console.aws.amazon.com/vpc/home +- click on `Your VPCs` on the left navigation +- copy the VPC ID which will have the format `VPC-b346eab3` +- click on `Subnets` on the left navigation +- copy your Subnet IDs which will have the format `SUBNET-12456c55` + - If you only have two Subnets, simply remove `SUBNET_ID_C` from the environment file and from + `serverless.yml` + +You can set the `DB` fields to anything you'd like. These settings will be used when creating the +RDS instance on the initial deployment. + + +# Setting up front-end + +The front-end code is based on create-react-app. + +You will need to set the BASE_URL in `src/constants.js` to be the base URL of your deployed API +from the steps above. + +To buid the UI: + +``` +$ cd ui +$ yarn && yarn start +``` + +Setting up the front-end application using CloudFormation is a bit more work. All of the instructions can be found in Chapter 2 under the section, _Setting up static assets_. + +You will need to have your own domain setup in Route53 if you follow along with those steps. + +**NOTE**, there is no UI which allows you to create new cupping sessionf from the UI. In order to +creat new data you'll need to use the raw API. You can do this with CURL, Postman or any other HTTP +tool of choice. A CURL example is shown below. Simply change the URL and it should work for you: + +```bash +curl -X POST \ + https://ffej1idill.execute-api.us-west-2.amazonaws.com/dev/session \ + -H 'Cache-Control: no-cache' \ + -H 'Content-Type: application/json' \ + -d '{ + "name": "Friday AM session", + "formName": "Modified COE", + "cuppings": [ + { + "name": "Guat Huehuetenango", + "overallScore": "88.5", + "scores": { + "Aroma": 8.6, + "Body": 8, + "Flavor": 10 + }, + "notes": "This was pretty good", + "descriptors": ["woody", "berries"] + }, + { + "name": "Ethiopia Yiracheffe", + "overallScore": "90", + "scores": { + "Aroma": 8.6, + "Body": 8, + "Flavor": 10 + }, + "notes": "", + "descriptors": ["blueberry"] + } + ] +}' +``` + +# Destroying the stack + +From within the Docker container: + +```bash +root@675d2d42e460:/code# cd serverless/ +root@675d2d42e460:/code/serverless# sls remove -s $ENV +``` diff --git a/ch2/docker-compose.yml b/ch2/docker-compose.yml new file mode 100644 index 0000000..d8e8973 --- /dev/null +++ b/ch2/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3' +services: + db: + image: postgres:9.6-alpine + ports: + - 5532:5432 + serverless: + image: verypossible/serverless:1.25.0-python3 + environment: + - ENV + env_file: + - envs/${ENV} + volumes: + - .:/code diff --git a/ch2/serverless/cupping/constants.py b/ch2/serverless/cupping/constants.py index 96ee756..8078be8 100644 --- a/ch2/serverless/cupping/constants.py +++ b/ch2/serverless/cupping/constants.py @@ -11,12 +11,3 @@ DB_PASSWORD = os.environ.get('CUPPING_DB_PASSWORD', '') DB_PORT = os.environ.get('CUPPING_DB_PORT', 5432) DB_USERNAME = os.environ.get('CUPPING_DB_USERNAME', 'postgres') - -# try: -# encrypted_var = b64decode(os.environ.get('SECRET_VAR')) -# if encrypted_var: -# variable = boto3.client('kms').decrypt( -# CiphertextBlob=encrypted_var)['Plaintext'] -# print(variable) -# except Exception as e: -# print(e) diff --git a/ch2/tests/conftest.py b/ch2/tests/conftest.py index 6d1b97e..96af15e 100644 --- a/ch2/tests/conftest.py +++ b/ch2/tests/conftest.py @@ -16,29 +16,28 @@ os.environ.update({ 'CUPPING_DB_PASSWORD': '', 'CUPPING_DB_USERNAME': 'postgres', - 'CUPPING_DB_HOST': 'cupping-%s-postgres' % ENV, + 'CUPPING_DB_HOST': 'db', }) if os.environ.get('CIRCLECI'): os.environ['CUPPING_DB_HOST'] = 'localhost' os.environ['CUPPING_DB_NAME'] = 'cupping_test' - from cupping.models import ( - CuppingModel, - SessionModel, + CuppingModel, + SessionModel, ) from cupping.persistence import ( - Cupping, - Session, + Cupping, + Session, ) from cupping.db import ( - _clear_tables, - _drop_tables, - close_db, - get_session, - commit_session, - setup_db, + _clear_tables, + _drop_tables, + close_db, + get_session, + commit_session, + setup_db, ) @@ -99,7 +98,10 @@ def cuppings_dicts(): return [ { 'name': 'Huehue', - 'scores': {'Aroma': 8.6, 'Flavor': 5.5}, + 'scores': { + 'Aroma': 8.6, + 'Flavor': 5.5 + }, 'overallScore': 75, 'defects': ['stank', 'pu'], 'descriptors': ['honey', 'berry', 'mungy'], @@ -108,7 +110,10 @@ def cuppings_dicts(): }, { 'name': 'Kochere', - 'scores': {'Aroma': 5.6, 'Flavor': 8.4}, + 'scores': { + 'Aroma': 5.6, + 'Flavor': 8.4 + }, 'overallScore': 85, 'defects': [], 'descriptors': [], diff --git a/ch2/ui/package.json b/ch2/ui/package.json index 8df92e7..870549c 100644 --- a/ch2/ui/package.json +++ b/ch2/ui/package.json @@ -6,7 +6,7 @@ "react": "^16.0.0", "react-dom": "^16.0.0", "react-scripts": "1.0.16", - "semantic-ui-react": "^0.75.1" + "semantic-ui-react": "^0.79.1" }, "scripts": { "start": "react-scripts start", diff --git a/ch2/ui/src/MainContent.js b/ch2/ui/src/MainContent.js index 5bcb9f6..f853792 100644 --- a/ch2/ui/src/MainContent.js +++ b/ch2/ui/src/MainContent.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; -import { Segment, Header, Grid } from 'semantic-ui-react' +import { Segment, Header, Grid, Message } from 'semantic-ui-react' import CuppingTable from './CuppingTable' import './css/index.css' @@ -20,6 +20,10 @@ export default class MainContent extends Component { newCuppingPage() { return ( + + This is not yet implemented +

See the README for instructions on how to create a new cupping session.

+
New Cupping
) diff --git a/ch2/ui/src/constants.js b/ch2/ui/src/constants.js index 2f36df8..fbeca14 100644 --- a/ch2/ui/src/constants.js +++ b/ch2/ui/src/constants.js @@ -1 +1 @@ -export const BASE_URL = 'https://4mvnd1tewe.execute-api.us-west-2.amazonaws.com/dev' +export const BASE_URL = 'https://ffej1idill.execute-api.us-west-2.amazonaws.com/dev' diff --git a/ch2/ui/yarn.lock b/ch2/ui/yarn.lock index fc56183..b3bf2b9 100644 --- a/ch2/ui/yarn.lock +++ b/ch2/ui/yarn.lock @@ -5537,12 +5537,13 @@ selfsigned@^1.9.1: dependencies: node-forge "0.6.33" -semantic-ui-react@^0.75.1: - version "0.75.1" - resolved "https://registry.yarnpkg.com/semantic-ui-react/-/semantic-ui-react-0.75.1.tgz#81c2ed7ed45562f89e5049c5a64195b9638d8daf" +semantic-ui-react@^0.79.1: + version "0.79.1" + resolved "https://registry.yarnpkg.com/semantic-ui-react/-/semantic-ui-react-0.79.1.tgz#80bd0ccfb3b3c1184a1b1b3f6067ab1225aed5f0" dependencies: babel-runtime "^6.25.0" classnames "^2.2.5" + fbjs "^0.8.16" lodash "^4.17.4" prop-types "^15.5.10"