Vue.js & Express API | MyRecipeBook
Introduction
Cooking is hard, but you know what's harder? Remembering recipes. Remember that one time you made that amazing dish and forgot what ingredients go into it? It's a terrible feeling.
In this exercise, we'll make a an application to keep track of your favorite recipes so you never have this disappointing experience again.
This application can apply to food or dishes, so feel free to alter the language accordingly.
Instructions
You are going to make from scratch a web application recipe book with two parts: the front-end in Vue.js (Client) and the back-end in Express (Server).
Client
The users that go on your websites will have access to 4 possible routes:
/
: Redirect the user to/dishes
/dishes
: Display a list of all dishes, with a link/dishes/:dishId
: Display the recipe of a specific dish, with the descriptions and all it's ingredients/new-dish
: Display a form page to add a new dish
Example of page seen on "/dishes"
Example of page seen on "/dishes/598c147d82ff710a38fd6027"
Server
You are going to create your own Rest API with Express. For that, 2 models are going to be needed: Ingredient
and Dish
// server/models/ingredient.js
// ...
const IngredientSchema = new Schema({
name: {
type: String,
required: true
},
unity: String
});
module.exports = mongoose.model('Ingredient', IngredientSchema);
// server/models/dish.js
// ...
const DishSchema = new Schema({
name: {
type: String,
required: [true, 'name is required']
},
description: {
type: String,
required: [true, 'description is required']
},
image: String,
ingredients: [
{
ingredient: {
type: Schema.Types.ObjectId,
ref: 'Ingredient'
},
quantity: Number,
_id: false
}
]
});
module.exports = mongoose.model('Dish', DishSchema);
For your API, you can create the following endpoints:
GET /api/dishes
: Returns all dishes with only their id, names and imagesGET /api/dishes/:dishId
: Returns all information on a specific dishPUT /api/dishes/:dishId
: Updates a specific dishPOST /api/dishes
: Creates a new dish
To help you creating the database, there are 2 files with some data: data/dishes.json and data/ingredients.json
Iterations
Iteration 1 | Creating your first endpoint
To start, you will create an endpoint to list all dishes.
For that, you can:
- Initialize a new Express project inside starter-code/server/ folder
- Create your models
Dish
andIngredient
- Populate your database with data/dishes.json and data/ingredients.json
- Create the endpoint
GET /api/dishes
.
At the end of this iteration, you should see the following result when you go on localhost:3000/api/dishes
:
[
{
"_id": "598c147d82ff710a38fd6027",
"name": "Pizza",
"image": "https://i.imgur.com/eTmWoAN.png"
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
"_id": "598c147d82ff710a38fd6029",
"name": "Sweet Potato",
"image": "https://i.imgur.com/hGraGyR.jpg",
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
// ...
]
Iteration 2 | Listing dishes
Having a link to see all dishes in a JSON is a first good step and now we are going to use a Vue application. That's why we are now creating a dishes page (/dishes
) that will display all dishes in a list, with their names and images.
In that iteration, we recommand you to:
- Initialize a Vue application in starter-code/client/ folder
- Create a component that will be displayed on the following path
/dishes
- Fetch and display the dishes from
GET /api/dishes
- Redirect the home page (
/
) to/dishes
Iteration 3 | Show one dish details
You now have a list of dishes, it's time to link them to a detail page.
On your list of dishes page, create a link to /dishes/:dishId
that displays the name, the image and the description of a specific dish. You should also create an "Edit description" button just after your description.
Iteration 4 | Edit the description of a dish
In this iteration, we are going to edit the description without changing the page!
In term of user experience, the scenario should be the following:
- The user clicks on the "Edit description" button
- The text description is changed by a textarea with the description inside it add the button is changed by "Save description"
- When the user clicks on "Save description", it replaces the textarea by a simple paragraph, the "Edit description" button comes back and the new description must be saved
For that, you will probably need to create a PUT /api/dished/:dishId
endpoint.
Iteration 5 | List all ingredients
A dish detail page is nice, but we're missing one important piece: ingredients.
Over the next two iterations, we're going to add functionality to add ingredients to our dishes.
The first step in doing so is going to be displaying a list of possible ingredients on the recipe's page. For that, you will need to:
- Add an API endpoint
GET /api/ingredients
that displays all ingredients - Use this endpoint to display all your ingredients in your dish detail page (
/dishes/:dishId
)
In your list of all ingredients, you should display:
- The ingrendient's name
- A number input (will be used in the next iteration)
- The unity
- A "Add ingredient" button (will be used in the next iteration)
Iteration 6 | Add ingredient to dish
Create a function in the single dish component. When someone clicks the "Add ingredient" button from the previous iteration, it should add the ingredient to the dish and display it.
Do
The request should be done inside of your dish service.
The API endpoint is a POST to '/drinks/:drinkId/ingredients/:id/add'
. It also takes in a parameter for quantity
in the body, which is a number.
Add a list of a dish's ingredients to the single dish component. Upon successfully adding the ingredient to the dish, display the ingredient in the list.
Iteration 7 | Bonus | Creating New Ingredients & Dishes
Create a new route for adding new dishes. Add a link in the home page to display a form. This form will make a POST request to /dishes
with a name
, image
, and description
.
In addition, create a route on the home page to display a form to create a new ingredient. The route is a POST to /ingredients
, and takes a name
, image
, and description
in the body.