Skip to content

Commit

Permalink
api service push
Browse files Browse the repository at this point in the history
  • Loading branch information
gugzkumar committed Apr 12, 2019
1 parent 8be0bd9 commit c682546
Show file tree
Hide file tree
Showing 14 changed files with 412 additions and 2 deletions.
9 changes: 9 additions & 0 deletions api/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.ipynb
Dockerfile
api-construct.ts
*.js
*.d.ts
.ipynb_checkpoints
__pycache__
.DS_Store
cached-dependencies
21 changes: 21 additions & 0 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM jupyter/minimal-notebook:65761486d5d3

USER root
WORKDIR /app
RUN chown jovyan /app
RUN apt update
RUN apt install nodejs npm -y
RUN npm install -g nodemon@1.18.10

# Install dependencies
USER jovyan
RUN mkdir cached-dependencies
RUN pip install boto3 --user
RUN pip install flask-restful==0.3.7 --user
COPY ./requirements.txt /app/
RUN pip install -r requirements.txt --target=./cached-dependencies

# Copy api files from directory
COPY ./ /app

CMD ["start.sh", "jupyter", "notebook", "--NotebookApp.token=''"]
62 changes: 62 additions & 0 deletions api/api-construct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import cdk = require('@aws-cdk/cdk');
import apigateway = require('@aws-cdk/aws-apigateway');
import lambda = require('@aws-cdk/aws-lambda');
// import s3 = require('@aws-cdk/aws-s3');
import fs = require('fs');
import path = require('path');

const isFile = (fileName: any) => {
return fs.lstatSync(fileName).isFile();
}

export class ApiConstruct extends cdk.Construct {
public pythonDependencies: cdk.Construct;

constructor(parent: cdk.Construct, name: string) {
super(parent, name);
const api = new apigateway.RestApi(this, 'Api Gateway', {
restApiName: 'Boilerplate Web App Api',
description: 'This is API comes from a boilerplate web app'
});

// const slackBotDepenciesLayer =
this.pythonDependencies = new lambda.LayerVersion(this, 'Slackbot Dependencies', {
compatibleRuntimes: [lambda.Runtime.Python37],
code: lambda.Code.directory('./slackbot/myDependencies')
});

this.generateApiConstructs('api/endpoints/', api.root);
}


private generateApiConstructs(folderPath: any, apiResource: apigateway.IRestApiResource) {
// If folderPath path is not a file recursively call generateApiConstructs on all files in folderPath
if(!isFile(folderPath)) {
const apiChildResource = apiResource.addResource(path.basename(folderPath));
fs.readdirSync(folderPath).map((fileName) => {
this.generateApiConstructs(path.join(folderPath, fileName), apiChildResource);
});
return;
};
// If file is not a api config file exit method
if(!folderPath.endsWith('.api-config.json')) {
return;
}
// If file is a api config file create lambda function and api methods
const configs = require('../' + folderPath);
const basename = path.basename(folderPath, '.api-config.json');
const dirname = path.dirname(folderPath);
const params = {
runtime: lambda.Runtime.Python37,
code: lambda.Code.directory(dirname),
// layers: [slackBotLayer],
handler: `${basename}.main`
}
const lambdaFunction = new lambda.Function(this, folderPath.replace(/\//g, '_'), params);
const apiLambdaIntegration = new apigateway.LambdaIntegration(lambdaFunction);
configs['methods'].map((method: string) => {
apiResource.addMethod(method, apiLambdaIntegration);
});
return;
}
}
6 changes: 6 additions & 0 deletions api/endpoints/cats/cats.api-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"methods": [
"GET",
"POST"
]
}
38 changes: 38 additions & 0 deletions api/endpoints/cats/cats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import json

def get(event, context):
return {
"statusCode": 200,
"body": json.dumps({
'message': 'GET language',
'event': event
})
}

def post(event, context):
return {
"statusCode": 200,
"body": json.dumps({
'message': 'POST language',
'event': event
})
}

def main(event, context):
if event["httpMethod"] == "GET":
return get(event, context)
elif event["httpMethod"] == "POST":
return post(event, context)
elif event["httpMethod"] == "DELETE":
return delete(event, context)
elif event["httpMethod"] == "PUT":
return post(event, context)
else:
return {
"statusCode": 405,
"body": json.dumps(
{
"message": "Method Not Allowed"
}
)
}
5 changes: 5 additions & 0 deletions api/endpoints/cats/{breeds}/{breeds}.api-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"methods": [
"GET"
]
}
29 changes: 29 additions & 0 deletions api/endpoints/cats/{breeds}/{breeds}.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import json

def get(event, context):
return {
"statusCode": 200,
"body": json.dumps({
'message': 'GET Breed',
'event': event
})
}

def main(event, context):
if event["httpMethod"] == "GET":
return get(event, context)
elif event["httpMethod"] == "POST":
return post(event, context)
elif event["httpMethod"] == "DELETE":
return delete(event, context)
elif event["httpMethod"] == "PUT":
return post(event, context)
else:
return {
"statusCode": 405,
"body": json.dumps(
{
"message": "Method Not Allowed"
}
)
}
6 changes: 6 additions & 0 deletions api/endpoints/dogs/dogs.api-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"methods": [
"GET",
"POST"
]
}
40 changes: 40 additions & 0 deletions api/endpoints/dogs/dogs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import json
import numpy as np


def get(event, context):
return {
"statusCode": 200,
"body": json.dumps({
'message': 'GET test',
'event': event
})
}

def post(event, context):
return {
"statusCode": 200,
"body": json.dumps({
'message': 'POST test',
'event': event
})
}

def main(event, context):
if event["httpMethod"] == "GET":
return get(event, context)
elif event["httpMethod"] == "POST":
return post(event, context)
elif event["httpMethod"] == "DELETE":
return delete(event, context)
elif event["httpMethod"] == "PUT":
return post(event, context)
else:
return {
"statusCode": 405,
"body": json.dumps(
{
"message": "Method Not Allowed"
}
)
}
2 changes: 2 additions & 0 deletions api/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
numpy==1.16.0
pandas==0.24.0
155 changes: 155 additions & 0 deletions api/simple_lambda_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Add /cached-dependencies/ to importable path
import sys
import os
import importlib
import json

sys.path.append('./cached-dependencies')

from flask import Flask, request
from flask_restful import Api, Resource, reqparse
class Test(Resource):
def get(self):
print(self)
return 'SS', 200
app = Flask(__name__)
api = Api(app)


# Template JSON/Dicts that represent a AWS lambda events for every HTTP method
get_lambda_event_template = {
'httpMethod': 'GET',
'queryStringParameters': {},
'pathParameters': None,
'requestContext': {
'identity': {
'accessKey': None,
'accountId': None,
'caller': None,
'cognitoAuthenticationProvider': None,
'cognitoAuthenticationType': None,
'cognitoIdentityId': None,
'cognitoIdentityPoolId': None
}
}
}
post_lambda_event_template = {
'httpMethod': 'POST',
'body': {},
'queryStringParameters': {},
'pathParameters': None,
'requestContext': {
'identity': {
'accessKey': None,
'accountId': None,
'caller': None,
'cognitoAuthenticationProvider': None,
'cognitoAuthenticationType': None,
'cognitoIdentityId': None,
'cognitoIdentityPoolId': None
}
}
}
put_lambda_event_template = {
'httpMethod': 'POST',
'body': {},
'queryStringParameters': {},
'requestContext': {
'identity': {
'accessKey': None,
'accountId': None,
'caller': None,
'cognitoAuthenticationProvider': None,
'cognitoAuthenticationType': None,
'cognitoIdentityId': None,
'cognitoIdentityPoolId': None
}
}
}
delete_lambda_event_template = {
'httpMethod': 'POST',
'body': {},
'queryStringParameters': {},
'requestContext': {
'identity': {
'accessKey': None,
'accountId': None,
'caller': None,
'cognitoAuthenticationProvider': None,
'cognitoAuthenticationType': None,
'cognitoIdentityId': None,
'cognitoIdentityPoolId': None
}
}
}

endpoint_dir = './endpoints'


# Construct Flask API endpoints based on folder structure of endpoint folder
i=0
for path, dirs, files in os.walk(endpoint_dir):
i+=1
full_path = os.path.abspath(path)
current_folder_name = full_path.split(os.sep)[-1]
# If a python file for lambda function exists for the resource do the following:
if f'{current_folder_name}.py' in files:
api_resource_path = path.replace(endpoint_dir, '').replace('{', '<').replace('}', '>')
full_path_of_py_file = os.path.abspath(path) + f'/{current_folder_name}.py'

spec = importlib.util.spec_from_file_location("module.name", full_path_of_py_file)
current_lambda_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(current_lambda_module)


# Creating an Anonomys Class
class LambdaApiResource(Resource):
resource = api_resource_path
lambda_module = current_lambda_module
get_lambda_event = get_lambda_event_template.copy()
post_lambda_event = post_lambda_event_template.copy()
put_lambda_event = put_lambda_event_template.copy()
delete_lambda_event = delete_lambda_event_template.copy()

def get(self, **kwargs):
print(request.args)
get_lambda_event = self.get_lambda_event.copy()
get_lambda_event['pathParameters'] = kwargs
get_lambda_event['queryStringParameters'] = {key:val for key, val in request.args.items()}
lambda_result = self.lambda_module.main(
get_lambda_event,
None
)
return json.loads(lambda_result['body']), lambda_result['statusCode']
def post(self, **kwargs):
post_lambda_event = self.post_lambda_event.copy()
post_lambda_event['pathParameters'] = kwargs
post_lambda_event['queryStringParameters'] = {key:val for key, val in request.args.items()}
lambda_result = self.lambda_module.main(
post_lambda_event,
None
)
return json.loads(lambda_result['body']), lambda_result['statusCode']
def put(self, **kwargs):
put_lambda_event = self.put_lambda_event.copy()
put_lambda_event['pathParameters'] = kwargs
put_lambda_event['queryStringParameters'] = {key:val for key, val in request.args.items()}
lambda_result = self.lambda_module.main(
put_lambda_event,
None
)
return json.loads(lambda_result['body']), lambda_result['statusCode']
def delete(self, **kwargs):
delete_lambda_event = self.delete_lambda_event.copy()
delete_lambda_event['pathParameters'] = kwargs
delete_lambda_event['queryStringParameters'] = {key:val for key, val in request.args.items()}
lambda_result = self.lambda_module.main(
post_lambda_event,
None
)
return json.loads(lambda_result['body']), lambda_result['statusCode']

LambdaApiResource.__name__ = f'Lambda{i}'
api.add_resource(LambdaApiResource, api_resource_path)

app.run(host='0.0.0.0', port=10000, debug=True)
4 changes: 2 additions & 2 deletions client-ui/angular-code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"start": "ng serve --host 0.0.0.0 --disable-host-check --watch --poll 500",
"build": "ng build --watch --poll 500 --outputPath=../angular-output",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
Expand Down
Empty file removed client-ui/angular-output/.gitkeep
Empty file.
Loading

0 comments on commit c682546

Please sign in to comment.