dchicchon / colaco

Full Stack application utilizing React

Home Page:https://dchicchon.github.io/colaco/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ColaCo

Summary

This monorepo hosts a full-stack application that can build a soda machine application. The client dispenses soda jsons from a virtual soda machine and the server hosts an api where an owner can manage their machine through an interface. The application utililzes the MVC framework as its architecture.

To follow along with the below steps, be sure to use the stack branch. The main branch here is dedicated to the demo site running in Github Pages

Table of Contents

  1. Installation
  2. Start
  3. Client
  4. Server
  5. Production
  6. Links

Photos


Client

API Interface

Installation

Before running this application, please ensure that your device has the latest version of NodeJS

Start

Quickstart

To start this application, run:

npm run quickstart

This will install all the dependencies for the application then concurrently begin the client and api development servers. By default, the client will be hosted on http://localhost:3000, the api interface on http://localhost:3001, and the api on http://localhost:4000. The database should also be seeded by this point as well

Client

Summary

The client of this project is a React application that displays an SVG soda machine that contains a list of sodas retrieved from the server through an api call.

User Actions

Purchase Soda

On the client, a user can purchase sodas from the vending machine by clicking the button. Upon clicking the button, an api call will be sent to the server requesting to purchase a soda. Upon successful purchase, the browser will trigger the download of soda.json which will contain the id, label and description of the soda. In addition to the download, a message will appear on the side of the machine stating the soda label purchased.

API calls used

  • GET /api/sodas: retrieves the list of sodas available from the database
  • PUT /api/sodas: decrements the type of soda purchased then returns the soda information to download as json

Stretch Goals

  • Utilize polling through useInterval to fetch new content over time
  • Utilize React lazy, Suspense to take advantage of code splitting and allow the client to load components as needed with webpack
  • Utilize React Error Boundary to catch JavaScript errors and display fallback UI
  • Add additional styling with SVGs or Three.js to page in order to keep users more engaged.

Server

Summary

The server is a NodeJS application utilizing the web framework Express to host an API for the client. To simplify the managment of the soda machine, an interface built with React was used to interact with the API.

Interface

Summary

The interface displays information to the admin that includes the Soda listings, Transactions placed, and Revenue earned. The admin additionally can interact with the API directly here.

User Actions

Create Soda

An admin can create a soda by clicking on the Add Soda button. This will bring up a modal that will request input from the admin to create the soda. On submit, a POST request will be sent to /api/sodas and will respond with the soda created

Update Soda

An admin can update a soda utilizing the same modal by clicking the Update Soda button. On sumbit, a PUT request will be sent to /api/sodas/:id and will respond with how many rows were updated.

Delete Soda

An admin can delete a soda by clicking the Update Soda button then on the modal click the Delete Soda button. This will send a DELETE request to /api/sodas:id and will respond with the result of the deletion

API calls used

  • GET /api/sodas to retrieve all sodas from the database
  • GET /api/transactions/ to retrieve all transactions from the database
  • GET /api/revenue to retrieve the current revenue of the soda machine
  • POST /api/sodas to add a soda to the database
  • PUT /api/sodas/:id to update a soda
  • DELETE /api/sodas/:id to delete a soda inthe database

Stretch Goals

  • Include authentication to only allow soda machine admins to access the API. Either through a environment variable as a password or by creating admins in the database.
  • Include a timeline of the soda machine revenue to analyze the most profitable times.
  • Include a table of most purchased sodas to anaylze which sodas were the most popular
  • Include pagination to our transaction and soda tables to allow admin to not have to request such a large amount of data from the server at one time.
  • Create more tests to ensure quality of code.

API

Summary

The API is built with the Express web framework and Sequelize ORM. It is structured as follows

- controllers 
- db
- models
- routes
- tests
- testUtils
- utils
app.js
server.js

The API is structured to modularize the code and allow testing on individual files. An example of testing an express app can be found here

Available Routes

Title Get Sodas
Method GET
URL /api/sodas
URL Parameters None
Success Response Code: 200
Content: [{id: '1', label: 'Pop', description: 'A soda', price: 1.00, quantity: 100 }, ...]
Error Response Code: 400 BAD REQUEST
Content: None
Sample Request curl http://localhost:4000/api/sodas
Notes Returns a list of sodas

Title Get Transactions
Method GET
URL /api/transactions
URL Parameters None
Success Response Code: 200
Content: [{id: '1', label: 'Pop', price: 1.00, time: 12/18/2021, 3:02:21 PM }, ...]
Error Response Code: 400 BAD REQUEST ERROR
Content: None
Sample Request curl http://localhost:4000/api/transactions
Notes Returns a list of transactions

Title Get Revenue
Method GET
URL /api/revenue
URL Parameters None
Success Response Code: 200
Content: [{revenue: 9.00}]
Error Response Code: 400 BAD REQUEST
Content: None
Sample Request curl http://localhost:4000/api/revenue
Notes Returns the revenue of the soda machine

Title Add Soda
Method POST
URL /api/sodas
URL Parameters Required:
{label: [String], price: [Float], description: [String], quantity: [Integer]}
Success Response Code: 200
Content: {id: 1, label: 'Pop', price: 1.00, description: 'A soda', quantity: 100}
Error Response Code:400 BAD REQUEST
Content: None
Sample Request curl -X POST -H "Content-Type: application/json" -d '{"label":"pop","price":1.00,"description":"niceSoda", "quantity":100}' http://localhost:4000/api/sodas
Notes Adds a soda

Title Buy Soda
Method PUT
URL /api/sodas
URL Parameters Required:
{id: [id]}
Success Response Code: 200
Content: [1,0]
Error Response Code: 400 BAD REQUEST
Content: {"error":"No more soda to dispense"}
Sample Request curl -X PUT -H "Content-Type: application/json" -d '{"id": [id]}' http://localhost:4000/api/sodas
Notes Decrements the soda quantity

Title Update Soda
Method PUT
URL /api/sodas/:id
URL Parameters Required:
{id: [id], label: [String], price: [Float], description: [String], quantity: [Integer]}
Success Response Code: 200
Content: [1,0]
Error Response Code: 400 BAD REQUEST
Content: None
Sample Request curl -X PUT -H "Content-Type: application/json" -d '{"label":"Poppy","price":1.50,"description":"A new Soda", "quantity":150"}' http://localhost:4000/api/sodas/[id]
Notes Updates a soda

Title Delete Soda
Method DELETE
URL /api/sodas/:id
URL Parameters Required:
{id: [id]}
Success Response Code: 200
Content: [1]
Error Response Code: 400 BAD REQUEST
Content: None
Sample Request curl -X DELETE http://localhost:4000/api/sodas/[id]
Notes Deletes a Soda

Database

For development of this application, SQLite was used due to its flexibility as a zero-configuration and self-contained database engine.

In production, it is recommended to utilize a SQL Database engines such as MySQL, PostGreSQL, etc. For my deployment of this application, I utilized MySQL through the provisioning of JAWSDB on Heroku

SQL vs NoSQL

In the development of this project, a SQL Database was utilized as the main platform for hosting the data. In hindsight, I believe that a NoSQL database would have been the correct choice due to the flexibility of data models and because my application does not require any relational mapping of the tables.

Models

This application relies on the Data Models of Soda and Transaction.

Soda {
  label: String,
  price: Number,
  description: String,
  quantity: Number
}

Transaction {
  label: String,
  price: Number
}

The models are then created as instances via Sequelize

Stretch Goals

  • In the API for purchasing a soda, the api is sending back an object that is a representation of the soda purchased. The client then creates an a tag to initiate the function downloadJSON to download the JSON file on the client. This method utilizes more resources on the browser and may stress mobile clients. It would be more appropriate to download from the server itself utilizing the method res.download
  • Convert database solution to utilize mongoose package since current application does not rely extensibly on relational mapping and it would be beneficial to have a more flexible data model.
  • Transfer application to a Docker container to make it an executable that can run in any environment
  • Configure cors options to only accept origins for client
  • Create more tests to ensure quality of code.

Production

To deploy this application I utilized Heroku since they provide add-ons for production SQL databases such as JAWSDB that can easily be placed into the API. If no JAWSDB

Configuration

The Client during development utilizes the Server endpont http://localhost:4000 for requests. For deployment, ensure that you set the .env variable REACT_APP_BASE_URL to your production server. On the Heroku application dashboard, this can be found in settings under the section Config Vars.

Deployment

To deploy this application, be sure to have the Heroku CLI installed. Since this project is a monorepo, we will deploy the client and server individually as their own applications via Git Subtrees

Client

  1. Create a Heroku application
heroku create <optional-name>
  1. Utilizing the project endpoint, create a new git remote through this command
git remote add client <client-heroku-endpoint>
  1. Push the project the client remote via
npm run deploy-client

Server

  1. Create a Heroku application
heroku create <optional-name>
  1. Utilizing the project endpoint, create a new git remote through this command
git remote add server <server-heroku-endpoint>
  1. Push the project the server remote via
npm run deploy-server

Available Scripts

npm run quickstart    - runs install script then start script
npm run install       - install dependencies in application
npm start             - runs seed script and develop script
npm run develop       - starts client and api development servers
npm run client        - starts client development server
npm run server        - starts server api and interface servers
npm run seed          - seeds sqlite database
npm run deploy:client - deploys client build to heroku endpoint
npm run deploy:server - deploys server build to heroku endpoint
npm run lint          - runs linter on client and server
npm run test          - runs tests on client and server
npm run prepare       - prepares git hooks with husky
npm run build         - runs build scripts of client and api-interface

Technologies Used

  • React: JavaScript Framework for UI Interfaces
  • Sequelize: Object Relational Mapper for SQL
  • NodeJS: JavaScript Server Runtime Environment
  • Express: JavaScript Web Framework
  • Heroku: Cloud Application Platform to applications
  • ESLint: JavaScript Linter to identify issues and conform style
  • Husky: NPM package to run project scripts with Git Hooks
  • Axios: promise based HTTP client for the Browser and NodeJS
  • CORS: NPM package to enable Cross Origin Resource Sharing on the server.

Project Stretch Goals

  • Utilize Continuous Integration in the project for future codebase development.
  • Several eslint configs have rules turned off, turn them on in the future

Links

Client
Server

About

Full Stack application utilizing React

https://dchicchon.github.io/colaco/


Languages

Language:JavaScript 86.7%Language:CSS 12.2%Language:HTML 1.1%