Skip to content

calvinlfer/Weather-Manager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Weather manager

A simple REST API that is meant to manage a set of weather related data for a user.

Architecture

Authentication

This application makes use of JWT tokens to perform authentication. JWT tokens must be included in the Authorization header field (with value Bearer <token>) when trying to access protected endpoints. The HS256 algorithm for decoding and verifying JWT tokens which relies on secret text being shared.

Reset code via email is made possible by Courier. We rely on an existing SMTP compatible mail server (like GMail) to send out emails to users.

Application

The application uses Akka HTTP to serve HTTP requests and DynamoDB as the backing store. It also interacts with OpenWeather in order to source weather information. ScalaCache + Caffeine is also used to cache OpenWeather queries for 30 minutes to minimize latency and bandwidth.

It uses 3 DynamoDB tables:

  • Member: responsible for member authentication (passwords are bcrypted and then stored)
  • Forecast: OpenWeather forecast weather ID data is stored for each user
  • Password Reset: Table that is used to facilitate password reset functionality

Table Creation

If you are using local DynamoDB, hop on to the shell (eg. if Local DynamoDB runs on port 8000, visit http://localhost:8000/shell) and execute the following commands to configure the tables:

Table to store forecast data

var params = {
    TableName: 'forecast',
    KeySchema: [ // The type of of schema.  Must start with a HASH type, with an optional second RANGE.
        { // Required HASH type attribute
            AttributeName: 'username',
            KeyType: 'HASH',
        },
        { // Optional RANGE key type for HASH + RANGE tables
            AttributeName: 'id', 
            KeyType: 'RANGE', 
        }
    ],
    AttributeDefinitions: [ // The names and types of all primary and index key attributes only
        {
            AttributeName: 'username',
            AttributeType: 'S', // (S | N | B) for string, number, binary
        },
        {
            AttributeName: 'id',
            AttributeType: 'N', // (S | N | B) for string, number, binary
        }
    ],
    ProvisionedThroughput: { // required provisioned throughput for the table
        ReadCapacityUnits: 1, 
        WriteCapacityUnits: 1, 
    }
};
dynamodb.createTable(params, function(err, data) {
    if (err) ppJson(err); // an error occurred
    else ppJson(data); // successful response
});

Table to store member data

var params = {
    TableName: 'forecast-members',
    KeySchema: [ // The type of of schema.  Must start with a HASH type, with an optional second RANGE.
        { // Required HASH type attribute
            AttributeName: 'email',
            KeyType: 'HASH',
        }
    ],
    AttributeDefinitions: [ // The names and types of all primary and index key attributes only
        {
            AttributeName: 'email',
            AttributeType: 'S', // (S | N | B) for string, number, binary
        }
    ],
    ProvisionedThroughput: { // required provisioned throughput for the table
        ReadCapacityUnits: 1, 
        WriteCapacityUnits: 1, 
    }
};
dynamodb.createTable(params, function(err, data) {
    if (err) ppJson(err); // an error occurred
    else ppJson(data); // successful response
});

Table to store password reset data

var params = {
    TableName: 'forecast-password-reset',
    KeySchema: [ // The type of of schema.  Must start with a HASH type, with an optional second RANGE.
        { // Required HASH type attribute
            AttributeName: 'resetCode',
            KeyType: 'HASH',
        }
    ],
    AttributeDefinitions: [ // The names and types of all primary and index key attributes only
        {
            AttributeName: 'resetCode',
            AttributeType: 'S', // (S | N | B) for string, number, binary
        }
    ],
    ProvisionedThroughput: { // required provisioned throughput for the table
        ReadCapacityUnits: 1, 
        WriteCapacityUnits: 1, 
    }
};
dynamodb.createTable(params, function(err, data) {
    if (err) ppJson(err); // an error occurred
    else ppJson(data); // successful response
});

Running the application

The easiest way to run the application is using IntellIJ, if you want to run this against local DynamoDB then add the following to the VM properties in the Run Configuration:

-Dsecrets.jwt-key=examplesecretgoes here -Ddynamodb.aws-access-key-id=dev -Ddynamodb.aws-secret-access-key=dev -Ddynamodb.endpoint=http://localhost:8000 -Demail.sender-email=youremail@gmail.com -Demail.password=yourpassword -Dopenweather.api-key=youropenweatherapikey

You can also use the universal packager which is more geared for production deployment

sbt clean universal:packageBin 

Navigate to target/universal and unzip weather-manager-1.0.zip and execute ./bin/weather-manager and ensure the following environment variables are present:

  • FORECAST_TABLE: name of table to manage forecast data for users
  • MEMBER_TABLE: name of table to manage user authentication
  • PASSWORD_RESET_TABLE: name of table to handle password resets for users
  • SMTP_SERVER: domain of SMTP server (e.g. smtp.gmail.com)
  • SMTP_PORT: port of SMTP server
  • SENDER_EMAIL: email that is used to send password resets
  • SENDER_PASSWORD: password belonging to the email
  • JWT_SECRET: the secret used to encrypt JWT messages
  • JWT_EXPIRY: the time (in seconds) that the JWT token is valid for

If you want to run this against local DynamoDB then ensure you have these system properties as well:

-Ddynamodb.aws-access-key-id=dev -Ddynamodb.aws-secret-access-key=dev -Ddynamodb.endpoint=http://localhost:8000

You can also use the system properties mentioned above as an alternative to environment variables. For example:

./bin/weather-manager -Dsecrets.jwt-key=examplesecretgoes here -Ddynamodb.aws-access-key-id=dev -Ddynamodb.aws-secret-access-key=dev -Ddynamodb.endpoint=http://localhost:8000 -Demail.sender-email=youremail@gmail.com -Demail.password=yourpassword -Dopenweather.api-key=youropenweatherapikey

About

A simple Weather Manager application using Akka HTTP and DynamoDB that interacts with OpenWeather

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published