Example application
===================

An example application is provided in the Github repository of this library.
To deploy it or to modify it for experimentation, you can download the repository in one of the following ways:

* using git: ``git clone https://github.com/shlublu/awsmate.git``
* manually: ``zip`` and ``tar.gz`` archives are available on the `release page of the repository <https://github.com/shlublu/awsmate/releases>`_

Prerequisites
-------------

To deploy and run this application, you will need:

* an AWS account with valid credentials to create, modify and destroy AWS resources
* a Linux shell able to use ``curl`` and ``unzip``. This can either be a native one or a Cygwin or equivalent should you be using Windows.

Example files location
----------------------

::

    awsmate
        |___example
                |
                |___deploy.sh
                |
                |___undeploy.sh
                |
                |___ ...
                |
                |___src/ (Python sources of this example application)                    
                |
                |___tf/ (Terraform sources of this example application)


Instructions for deployment
---------------------------

AWS settings
~~~~~~~~~~~~

* Using configuration and credentials files:
    *   define a default profile in ``~/.aws/``, or use the AWS CLI ``aws configure`` command
    *   please see the `AWS documentation of these configuration files <https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html>`_  for further details
* Using environment variables: 
    *   define your AWS IAM credential using the environment variables ``AWS_ACCESS_KEY_ID``, ``AWS_SECRET_ACCESS_KEY``, (...)  
    *   define the AWS region you wish to deploy in using the environment variable ``AWS_REGION``
    *   export all these environment variables using the shell ``export`` command
    *   please see the `AWS documentation of these environment variables <https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html>`_  for further details

In some companies and organizations you may have to use the AWS CLI to execute commands such as ``aws sts assume-role`` or ``aws sso login`` on top of or instead of the above. Should you have issues defining your AWS settings, please check with your AWS administrator.

.. _Deployment:

Deployment
~~~~~~~~~~

From the ``example`` directory seen above:

* run ``./deploy.sh``: this will deploy all AWS resources described in the ``tf/`` directory. This may take some time, and this produces a pretty verbose log.
* then take note of the final log message ``endpoint_url = "https://<deployment id>.execute-api.<region>.amazonaws.com/v0"``: this is the base URL of the newly deployed example API. 

The :ref:`section "Application users's guide" <UsersGuide>` below explains how to use this example application.

**Caveats** 

**Security**: The example API is accessible from the whole internet to anyone who would find its URL. We recommend undeploying the example application after 
use (see :ref:`section "Undeployment" <Undeployment>` below) to avoid any unexpected use or hack attempt. 
The URL of the API is generated by AWS at creation time, which makes it change each time you undeploy/redeploy the example application.

**awsmate upgrades**: Terraform version and example application structure may change from an ``awsmate`` version to another. We recommend undeploying 
the example application before upgrading it in order to avoid any compatibility issue.

.. _Undeployment:

Undeployment
~~~~~~~~~~~~

From the ``example`` directory above, run:

* ``./undeploy.sh``: this will destroy all AWS resources created by ``./deploy.sh``. This may take some time.

.. _UsersGuide:

Application users's guide
-------------------------

This example application demonstrates the various modules of the ``awsmate`` library:

API Gateway features: :doc:`apigateway<apigateway>` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Relevant source files

::

    awsmate
        |___example
                |
                |___src
                     |
                     |___lambda_apigateway_returns_okay.py
                     |
                     |___lambda_apigateway_returns_403.py
                     |
                     |___lambda_apigateway_returns_500.py


* Use

    The ``<endpoint_url>`` placeholder below need replacing by the actual value returned by ``./deploy.sh``, as seen in :ref:`section "Deployment" <Deployment>` above.

    * Route "okay": ``lambda_apigateway_returns_okay.py``
        * Command-line with ``curl`` 
            * ``curl -v -X <method> https://<endpoint_url>/okay/<any path>?<any url parameter>=<any value> --data '<any JSON payload>' --header '<any name>: <any value>'`` 
            * Example: ``curl -v -X POST https://<endpoint_url>/okay/lets/go?someParam=someValue --data '{ "someKey": 42 }' --header 'X-example: 42'``
            * Returns 200 with a JSON payload that contains the result of all methods of ``awsmate.apigateway.LambdaProxyEvent`` plus the raw event received from AWS API Gateway.
            * Demonstrates
                * the use of all methods of :class:`awsmate.apigateway.LambdaProxyEvent`,
                * the use of the HTTP response builder :func:`awsmate.apigateway.build_http_response`
            * Tip: play with the ``Accept`` and ``Accept-Encoding`` headers, play with the routes, play with the URL parameters
        * With a web browser
            * ``https://<endpoint_url>/okay/<any path>?<any url parameter>=<any value>``
            * Example: ``https://<endpoint_url>/okay/lets/go?someParam=someValue``
            * Returns an HTML page that is an HTML transformation of the JSON payload described in the command-line example just above.
            * Demonstrates 
                * the same of the above, plus
                * the use of the ``custom_transformers`` (here: HTML transformation of the API response) described in :doc:`the apigateway module documentation <apigateway>`,
                * the use of ``extra_headers`` (here: to handle CORS) with :func:`awsmate.apigateway.build_http_response`,
                * the ``gzip`` built-in functionality of :func:`awsmate.apigateway.build_http_response` based on the ``Accept-Encoding`` header (unless your browser does not accept gzip!),
                * the handling of preferences submitted through ``Accept*`` headers in `weighted quality value syntax <https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation>`_.
            * Tip: think of how you could localize the returned content depending on the ``Accept-Language`` header submitted by the browser
    * Route "forbidden": ``lambda_apigateway_returns_403.py``
        * Command-line with ``curl`` 
            * ``curl -v -X GET https://<endpoint_url>/forbidden' --header '<any name>: <any value>'`` 
            * Example: ``curl -v -X GET https://<endpoint_url>/forbidden``
            * Returns 403 with a JSON payload that explains the access is forbidden
            * Logs an error message in AWS Cloudwatch. See :ref:`section "Logger features" <LoggerFeatures>` below for further details.
            * Demonstrates
                * the use of the HTTP response builder :func:`awsmate.apigateway.build_http_client_error_response`
        * With a web browser
            * ``https://<endpoint_url>/forbidden``
            * Example: ``https://<endpoint_url>/forbidden``
            * Returns an HTML page that is an HTML transformation of the JSON payload described in the command-line example just above.
            * Demonstrates 
                * the same of the above plus the same extras seen with the "okay" route above
    * Route "crash": ``lambda_apigateway_returns_500.py``
        * Command-line with ``curl`` 
            * ``curl -v -X GET https://<endpoint_url>/crash' --header '<any name>: <any value>'`` 
            * Example: ``curl -v -X GET https://<endpoint_url>/crash``
            * Returns 500 with a JSON payload explaining that an internal error occurred
            * Logs a complete stack trace of this crash in AWS Cloudwatch. See :ref:`section "Logger features" <LoggerFeatures>` below for further details.
            * Demonstrates
                * the use of the HTTP response builder :func:`awsmate.apigateway.build_http_server_error_response` 
                * how not to reveal the cause of the crash to the end user (which would be a security breach) while logging it for debugging purposes
        * With a web browser
            * ``https://<endpoint_url>/crash``
            * Example: ``https://<endpoint_url>/crash``
            * Returns an HTML page that is an HTML transformation of the JSON payload described in the command-line example just above.
            * Demonstrates 
                * the same of the above plus the same extras seen with the "okay" route above                


EventBridge features: :doc:`eventbridge <eventbridge>` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Relevant source files

::

    awsmate
        |___example
                |
                |___src
                     |
                     |___lambda_eventbridge_scheduler.py


* Use
    * Step by step instructions
        * Go to the Cloudwatch service page of the AWS Console
        * Follow the "Logs/Log group" link of the left navigation panel
        * Search for the ``/aws/lambda/awsmate_eventbridge_scheduler`` log group and open it
        * Open the most recent log stream (the scheduler triggers an event every 5 minutes)
        * This show a log that contains the result of all methods of :class:`awsmate.eventbridge.LambdaBridgePutEvent` plus the raw event received from the AWS EventBridge service.
    * This demonstrates
        * the use of all methods of :class:`awsmate.eventbridge.LambdaBridgePutEvent`
    
Lambda Function features: :doc:`lambdafunction <lambdafunction>` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*Nothing for now*

S3 features: :doc:`s3 <s3>` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Relevant source files

::

    awsmate
        |___example
                |
                |___src
                     |
                     |___lambda_s3_notification.py


* Use
    * Step by step instructions
        * Go to the S3 service page
        * Open the page of the S3 bucket ``awsmate-drop-files-here-<your AWS account number>``
        * Upload a file into this bucket
        * Go to the Cloudwatch service page of the AWS Console
        * Follow the "Logs/Log group" link of the left navigation panel
        * Search for the ``/aws/lambda/awsmate_s3_notification`` log group and open it
        * Open the most recent log stream
        * This show a log that contains the result of all methods of :class:`awsmate.s3.LambdaNotificationEvent` plus the raw event received from the AWS S3 service.
    * This demonstrates
        * the use of all methods of :class:`awsmate.s3.LambdaNotificationEvent`
    * Tip: try to delete a file from the S3 bucket and see the corresponding log, try to drop or delete several files in a single action


.. _LoggerFeatures:

Logger features: :doc:`logger <logger>` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Relevant source files

::

    awsmate
        |___example
                |
                |___src
                     |
                     |___lambda_logger.py 


* Use
    * Step by step instructions
        * Go to the Lambda service page of the AWS Console
        * Follow the "Functions" link of the left navigation panel
        * Search for the ``awsmate_logger`` function and open it
        * Use the "Test" button to run it once. This will lead you to create a test event if not done already: any payload can be used as the event is not used by this function.
        * Go to the Cloudwatch service page of the AWS Console
        * Follow the "Logs/Log group" link of the left navigation panel
        * Search for the ``/aws/lambda/awsmate_logger`` log group and open it
        * Open the most recent log stream
        * This shows a log containing a series of messages of progressive log levels from INFO to CRITICAL, followed by a stack trace showing the details of a crash simulation.
    * This demonstrates
        * the use of the :data:`awsmate.logger.logger` object, which is a `standard Python logger <https://docs.python.org/3/library/logging.html>`_
        * the use of :func:`awsmate.logger.log_internal_error` 
