Car Share App

The customer demanded for these requirements in the project.
-- A way to store/update/pull code
--A place to host website and make updates
—A way for users to register and log in
—A way to do ride sharing functionality
—Somewhere to store/ return ride results
—A way to invoke ride sharing functionality

--Store the Code in GitHub this is the HTML CSS and JavaScript

Next step is that we need a place to host website and make updates.
So using Amplify(Gen 2) Used to host Built projects and host websites.
We can also use Amplify for Continuous Integration and Continuous Deployment (CI/CD) for auto updating any change to the project repo.

So in order to have CI/CD and Host, we need to use Amplify,
—select Github as our storage location,
— Then Amplify will ask for permissions to Github, select or
all repository access.
—and then Save and Deploy

So the backend stuff is being built in the background, like Ec2 instances.
You’ll be given a domain link and the website should start up. Amplify also allows CI/CD as well.
————————————————————————————————————
A way for user to register and Log in. Amazon Cognito is helpful for authentication and logging in and logging out and more.
So to start we go to Amazon Cognito

Create User pool

We will be using Cognito so change to Cognito default email address.
Then put a user pool name and App Client name.

Then create the user pool. Then click into the User pool.
—get the User Pool Id

and then go to App Integration and then scroll down

and get the Amazon Resource Number.

--Update the config file in the js folder with these credentials ( UserPoolId, userPoolClientId, region) this how the app knows work with the user pool in amazon cognito.

So now go on the website and put in example credentials, like email and password, to verify email. once authenticated then sign in and you should get an authentication token. Copy the Authentication Token use for later.

————————————————————————————————————
Somewhere to store return ride results
A way to do ride sharing functionality

In order to store the return ride results, using Dynamo Db which is a NoSQL, Key-Value database and contains a lighter setup as you don’t need a schema or setup relationships like many to one or one to one.

Then use Lambda which is code that that runs server less, so you dont need to manage servers, aws manages it automatically, and will respond upon some trigger, for example a code trigger whenever car request is received.

Go to Dynamodb to create a table.

Create a Dynamo Db table name and Partition Id

Then create table. Then click inside the table and additional information
and then copy DynamoDb Amazon Resource Number(ARN).

—————————————
So in order to start the Lambda function, the Lambda function will need to have the execution role permission to have the ability to write to the dynamo db table. So for that we go to IAM to create a role with the permissions that we then assign the Lambda function to have.

So first we go to IAM click roles

Then click on create roles.

Use case lambda, and then select AWSLambdaBasicExecutionRole as a policy. The policy allows Lambda functions to call AWS services on your behalf.

and then click next give the role a name. Click create role. Now that has been done. Search for your new role. Click into the new role, go to add permissions create inline policy.

We need to allow lambda the specific ability to put items into the Dynamodb
table. Also add the DynamoDb ARN go to text side and paste it in.

Name the policy name. Create the Policy.
——————————————
Now go to Lambda create function. Author from scratch

Name your function. Use Node.js 20.x. Change execution role put in the existing role that was just made. Create Lambda function.
Replace the code in the index.mjs file.

import { randomBytes } from 'crypto';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, PutCommand } from '@aws-sdk/lib-dynamodb';

const client = new DynamoDBClient({});
const ddb = DynamoDBDocumentClient.from(client);

const fleet = [
    { Name: 'Mike', Color: 'White', Gender: 'male' },
    { Name: 'Frank', Color: 'White', Gender: 'Male' },
    { Name: 'Janet', Color: 'Yellow', Gender: 'Female' },
];

export const handler = async (event, context) => {
    if (!event.requestContext.authorizer) {
        return errorResponse('Authorization not configured', context.awsRequestId);
    }

    const rideId = toUrlString(randomBytes(16));
    console.log('Received event (', rideId, '): ', event);

    // Because we're using a Cognito User Pools authorizer, all of the claims
    // included in the authentication token are provided in the request context.
    // This includes the username as well as other attributes.
    const username = event.requestContext.authorizer.claims['cognito:username'];


    // The body field of the event in a proxy integration is a raw string.
    // In order to extract meaningful values, we need to first parse this string
    // into an object. A more robust implementation might inspect the Content-Type
    // header first and use a different parsing strategy based on that value.   
    const requestBody = JSON.parse(event.body);
    const pickupLocation = requestBody.PickupLocation;
    const carride = findCarride(pickupLocation);

    try {
        await recordRide(rideId, username, carride);

        // You can use the callback function to provide a return value from your Node.js
        // Lambda functions. The first parameter is used for failed invocations. The
        // second parameter specifies the result data of the invocation.

        // Because this Lambda function is called by an API Gateway proxy integration
        // the result object must use the following structure.
        return {
            statusCode: 201,
            body: JSON.stringify({
                RideId: rideId,
                Carride: carride,
                Eta: '30 seconds',
                Rider: username,
            }),
            headers: {
                'Access-Control-Allow-Origin': '*',
            },
        };
    } catch (err) {
        console.error(err);

        // If there is an error during processing, catch it and return
        // from the Lambda function successfully. Specify a 500 HTTP status
        // code and provide an error message in the body. This will provide a
        // more meaningful error response to the end client.
        return errorResponse(err.message, context.awsRequestId);
    }
};

function findCarride(pickupLocation) {
    console.log('Finding car ride for ', pickupLocation.Latitude, ', ', pickupLocation.Longitude);
    return fleet[Math.floor(Math.random() * fleet.length)];
}

async function recordRide(rideId, username, carride) {
    const params = {
        TableName: 'Rides2',
        Item: {
            RideId: rideId,
            User: username,
            Carride: carride,
            RequestTime: new Date().toISOString(),
        },
    };
    await ddb.send(new PutCommand(params));
}

function toUrlString(buffer) {
    return buffer.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}

function errorResponse(errorMessage, awsRequestId) {
    return {
        statusCode: 500,
        body: JSON.stringify({
            Error: errorMessage,
            Reference: awsRequestId,
        }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    };
}

Then to test this code.

Paste this into the Json code and save. Deploy.

{
    "path": "/ride",
    "httpMethod": "POST",
    "headers": {
        "Accept": "*/*",
        "Authorization": "eyJraWQiOiJLTzRVMWZs",
        "content-type": "application/json; charset=UTF-8"
    },
    "queryStringParameters": null,
    "pathParameters": null,
    "requestContext": {
        "authorizer": {
            "claims": {
                "cognito:username": "the_username"
            }
        }
    },
    "body": "{\"PickupLocation\":{\"Latitude\":47.6174755835663,\"Longitude\":-122.28837066650185}}"
}

Then test. The response should be status 200.

You can then go to DynamoDb to click on your table and see the new items put in because of the test variables.

————————————————————————————————————
A way to invoke ride sharing functionality.

We tried invoking in test area, but we cannot expect users to do that so we need to setup api gateway so that users can interact with such code in the first place and send requests out. Api Gateway is used to build HTTPs and REST and websocket APIs.

We start by going to API gateway. Go to Rest Api.

Name your API and then create new API. Because we are using API Gateway we will need to use an Authorizer within Api Gateway.
API Gateway is then going to use Java Web Tokens(JWT) that are then return by Cognito.
In Api Gateway Left side pane click on Authorizers.

Authorizer Name and Authorizer Type is Cognito. Use the Cognito Userpool that was made previously. Token Source as Authorization. Create Authorizer.

This is where you can test your authorizer token from the Cognito website. You can copy and paste the long authorization token you had received when logging into the website previous.

Next is that we go to Resources, this is where the Lambda function will be hooked up to Amplify. Click on Resource in API Gateway and Create Resources.

make sure to enable Cross origin resource sharing , the domain on the site which we are getting from Amplify is different from the domain of API Gateway. Name resource path and create resource.

Method type Post, lambda, Select your lambda function and then create method. Put in Authorization.

Deploy the API.

Copy the invoke URL and then go to config.js file and paste.

Then go to Amplify click the Domain URL. Register and then add /ride.html to the remaining part of the URL, to get to Maps.