Pitch: This app is a basic food/meal/calorie tracking application.
Tech Pitch: This project is an introduction to true Gateway API Architecture. I am utilizing a front-end built in JavaScript which makes fetch calls to the Rails API endpoints.
- Database and Schema
- Versions/Prerequisites
- Setup
- The Test Suite
- Spinning Up A Server
- API End Points
- Authors
The database is a PostgreSQL database, made up of three tables.
The first is meals, which is seeded with:
- Breakfast
- Lunch
- Dinner
- Snack
The second is foods, which each contain a name and amount of calories.
And the third is MealFoods which is a joins table between meals and foods allowing a food to be a part of many meals and also allowing a meal to have many different foods.
To Install and run this application please be aware of the following versions and requirements:
- PostgreSQL 10+
- Rails 5.2.0
- Ruby 2.4.4
- ActiveRecord
- PG
- Puma
- First clone down this repository and change directory into the project directory:
git clone https://github.com/nergdnvlt/rails_quantified_self
cd fiver
- Then in your command line run bundle to install the gem dependencies:
bundle
- Now setup your database and run the migrations to properly set up your database tables:
rake db:create
rake db:migrate
- It's now time to seed the database with the required data:
rake db:seed
- At this point the project is set up. Explore at will.
- DatabaseCleaner
- FactoryBot
- Rspec
- ShouldaMatchers
- For additional documentation and the individual tests as the suite runs:
--format=documentation
The test suite includes test for the following:
- Model Level Testing
- API Request Testing
These tests can be found in the following folder:
spec/models/
spec/requests/api/v1/foods
spec/requests/api/v1/meals
- In order to run the test suite, from the root project folder simply run:
rspec
- Next spin up your server:
rails s
This is a restful API.
The food database includes full CRUD functionality at each of it's endpoints.
To get the foods index:
GET /api/v1/foods
The foods will be returned in as JSON to look like:
[
{
"id": 1,
"name": "Apple",
"calories": 150
},
{
"id": 2,
"name": "Banana",
"calories": 75
},
...
]
To get a single food:
GET /api/v1/foods/{food_id}
Example:
GET /api/v1/foods/1
will return a response body of:
{
"id": 1,
"name": "Apple",
"calories": 150
}
To create a food item send:
POST /api/v1/foods, params: { "food": { "name": "jerky", "calories": "250"} }
This will return the food item as JSON
NOTE: To update a food, you MUST pass both the name and calorie amount as parameters.
To update a food:
PATCH /api/foods/{food_id}, params: { "food": { "name": "jerky", "calories": "200"} }
To delete a food item:
DELETE /api/foods/{food_id}
It will return a message as JSON about the success of the deletion.
Meals has traditional RESTFUL routes for it's index and single meal.
To get the foods index:
GET /api/v1/meals
The meals will be returned in as JSON to look like:
[
{
"id": 1,
"name": "Breakfast",
"foods": [
{
"id": 1,
"name": "Banana",
"calories": 150
},
{
"id": 6,
"name": "Yogurt",
"calories": 550
},
{
"id": 12,
"name": "Apple",
"calories": 220
}
]
},
{
"id": 2,
"name": "Snack",
"foods": [
{
"id": 1,
"name": "Banana",
"calories": 150
},
{
"id": 9,
"name": "Gum",
"calories": 50
},
{
"id": 10,
"name": "Cheese",
"calories": 400
}
]
}
]
For the single meal endpoint, per the spec, I wanted to be clear that the foods were the main focus of the meal. So the path emphasizes the forcus on foods.
GET /api/v1/meals/{meal_id}/foods
The rest of the API's endpoints are to facilitate associating a food with a meal.
POST /api/v1/meals/{meal_id}/foods/{food_id}
This endpoint will route to the associated action (create) in the MealFoods controller and will create a database row associating the food to the meal. If successful it will return the following message:
{
"message": "Successfully added FOODNAME to MEALNAME"
}
To remove the association between a food and a meal make a delete request:
DELETE /api/v1/meals/:meal_id/foods/:id
It will return a JSON response of:
{
"message": "Successfully removed FOODNAME to MEALNAME"
}