2. Technology Behind The API - sight-hkust/ENGG4930C-ForeSee-mobile GitHub Wiki

ForeSee API is written in Python and designed to be deployed to AWS Lambda using Chalice.

The ENGG4930C-ForeSee-api repository README contains the instructions to get started.

Technology Behind

Lambda is an AWS service that enables you to run serverless code, which means you are responsible for writing the code and AWS is responsible for the execution. In order to use the code written in Lambda as an API, it needs to be connected to the internet using another AWS service API Gateway. The micro-framework Chalice enables you to deploy to Lambda from the command-line and takes care of the API Gateway itself.

The project also uses PyMySQL in order to perform operations on the database.

Structure

  1. app.py handles all the incoming API requests, (if needed) calls functions from chalicelib/rds.py, and returns respective values.
  2. chalicelib/rds.py contains all database related functions.
  3. chalicelib/rdsconfig.py contains the credentials to access the database. (Should be created locally not stored on Github)
  4. requirements.txt contains the record of necessary libraries.

Chalicelib

$ chalice deploy command only sends app.py and requiremets.txt; if you want to send any additional files to Lambda as well, they should be under chalicelib directory.

GET and POST Requests

The API gets triggered by both GET and POST requests via @app.route(...) decorator. Below is the decorator with parameters of /login which is a POST function.

@app.route('/login', methods=['POST'], content_types=['application/json'], cors=True)

On the other hand /get_user_records which is a GET request can be written as below.

@app.route('/get_user_doctors', methods=['GET'], cors=True)

Query Parameters

GET parameters can be directly accessed from app.current_request.query_params, but POST parameters need to be parsed with the following helper function.

def parse_post_parameters(raw_data):
    i_parsed_data = parse_qs(raw_data)
    parsed_data = {}
    for key in i_parsed_data:
        parsed_data[key] = i_parsed_data[key][0]

    return parsed_data

parse_post_parameters() returns a dictionary of query parameters and their values

RDS

All database operations are handled in chalicelib/rds.py with the function query_handler, which takes the query and a tuple of string variables. The function has distinct returns:

  1. SELECT operator returns a tuple of rows.
  2. SELECT operator with LIMIT 1 returns a single dictionary.
  3. INSERT operator returns the id of the inserted row.
def query_handler(query, variables=()):
    global conn
    try:
        cur = conn.cursor()
        if query.startswith("SELECT"):
            cur.execute(query, variables)
            if query.endswith("LIMIT 1"):
                result = cur.fetchone()
                return result
            else:
                results = cur.fetchall()
                return results
        else:
            cur.execute(query, variables)
            conn.commit()
            return cur.lastrowid
    except InterfaceError as err:
        conn = pymysql.connect(rds_host, user=name, passwd=password, db=db_name, connect_timeout=5,
                               cursorclass=cursors.DictCursor, charset='utf8mb4', autocommit=True)
        raise err
    except OperationalError as err:
        if err.args[0] == 2013:
            conn = pymysql.connect(rds_host, user=name, passwd=password, db=db_name, connect_timeout=5,
                                   cursorclass=cursors.DictCursor, charset='utf8mb4', autocommit=True)
        raise err

Further References

File Uploads

Currently, there are no file uploads integrated to the API but ideas depending on file uploads have been discussed a lot. The most secure and useful way of uploading a file to the AWS environment is using S3 Buckets with presigned URLs. Below is a list of resources that may be helpful.

  1. AWS's Official Documentation on S3 Presigned URLs
  2. Tutorial on S3 Presigned URLs by a Previous Member of the ForeSee SIGHT Team