Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ More details regarding the licensing history of this content can be found in [th

### Putting it all together

7. [Development environment](./introduction-to-nodejs/Putting-it-all-together/developement-process.md)
7. [Development environment](./introduction-to-nodejs/Putting-it-all-together/development-process.md)

### Milestone

9. [Milestone](./introduction-to-nodejs/milestone/README.md)
8. [Milestone](./introduction-to-nodejs/milestone/README.md)

## L2. Working with NPM

Expand All @@ -57,7 +57,7 @@ More details regarding the licensing history of this content can be found in [th
2. [What is NPM?](./working-with-npm/about-npm-and-uses/README.md)
3. [What is package.json](./working-with-npm/package-json-in-npm/README.md)
4. [What are NPM scripts](./working-with-npm/npm-scripts/README.md)
5. [Explore built in fs module](./working-with-npm/nodejs-fs-module/README.md)
5. [Explore built-in fs module](./working-with-npm/nodejs-fs-module/README.md)
6. [Explore streams](./working-with-npm/nodejs-stream-module/README.md)
7. [Working with npm install](./working-with-npm/npm-install-packages/README.md)
8. [Accepting command line arguments](./working-with-npm/accepting-cli-commands/README.md)
Expand Down Expand Up @@ -146,18 +146,18 @@ More details regarding the licensing history of this content can be found in [th
### Sequelize associations

1. [Introduction](./user-authentication/introduction/README.md)
2. [Create the `users` table with a sequelize migration]('./../user-authentication/create-users-table-with-sequelize-migration/README.md)
3. [Associations: adding owners to todo]('./user-authentication/../../user-authentication/associations-adding-owners-to-todo/README.md)
2. [Create the `users` table with a sequelize migration](./../user-authentication/create-users-table-with-sequelize-migration/README.md)
3. [Associations: adding owners to todo](./user-authentication/../../user-authentication/associations-adding-owners-to-todo/README.md)

### Signing up new users

4. [Creating a user sign-up page](./user-authentication/create-user-signup-page/README.md)
5. [Add user authentication using passport.js]('./../user-authentication/authentication-using-passport/README.md)
5. [Add user authentication using passport.js](./../user-authentication/authentication-using-passport/README.md)
6. [Storing passwords with bcrypt](./user-authentication/storing-password-using-bcrypt/README.md)

### Cookies, sessions, and the user authentication workflow

7. [Create a simple sign-in page which verifies the user's password]('./../user-authentication/signin-with-password-verification/README.md)
7. [Create a simple sign-in page which verifies the user's password](./../user-authentication/signin-with-password-verification/README.md)
8. [What exactly is a cookie and why should you care?](./user-authentication/why-cookies/README.md)
9. [Implement sign-out by resetting the user session](./user-authentication/sign-out/README.md)
10. [A logged-in user should see and modify only their own to-dos and nobody else's](./user-authentication/show-todos-for-logged-in-user/README.md)
Expand Down
203 changes: 113 additions & 90 deletions backend-dev-with-express/create-and-update-todo/README.md
Original file line number Diff line number Diff line change
@@ -1,158 +1,181 @@
# Text

Previously, you've learned, how to define routes in an **Express.JS** application. There we've also defined routes to create a TO-DO, update a TODO and to get details of a TO-DO. But the real implementation inside the callback function is not complete yet. And in this lesson we are about to do that. So, let's get started.

# Video Script
Hey there, in this video we will write some logic inside our route definitions, to *create* and *update* a TO-DO. We will also use Sequelize to persist our data in PostgreSQL database. And to test our routes, we will respond back in JSON format, as our user interface is not ready yet.


Hey there, in this video we will write some logic inside our route definitions, to _create_ and _update_ a TO-DO. We will also use Sequelize to persist our data in PostgreSQL database. And to test our routes, we will respond back in JSON format, as our user interface is not ready yet.

### Step 1: Define the TO-DO model using Sequelize
Before we can write logic inside our TO-DO endpoints, we have to define the **TODO** *model* using Sequelize.


Before we can write logic inside our TO-DO endpoints, we have to define the **TODO** _model_ using Sequelize.

To generate the **Todo** model, we will use the `db:generate` command of `sequelize-cli`. In this command, we have to pass the attributes of **Todo** along with their types. A **Todo** will have a `title` with type `string`, then `dueDate` of type `date` and a `complete` of type `boolean`.

```sh
npx sequelize-cli model:generate --name Todo --attributes title:string,dueDate:dateonly,completed:boolean
```

The above command will create a `todo.js` file in `model` folder and migration file in the `migrations` folder.

> Action: Show both files in VS Code

### Step 2: Create database table

The migration file has all the codes that we need to create the `Todos` table in the database. To simply run the migration file, we will execute the following command in the terminal:

```sh
npx sequelize-cli db:migrate
```

This will create the `Todos` table in the database.

> Action: Show the Todos table using PGAdmin.

### Step 3: Complete the `create Todo` endpoint implementation

### Step 3: Completed the `create Todo` endpoint implementation

In order to perform any operation for Todo, first we have to import the model in our primary `index.js` file.

```js
const { Todo } = require("./models");
```
Next, in the **create TODO** endpoint, we have to read the request body to look for the To-Do *title* and *dueDate*.

Next, in the **create TODO** endpoint, we have to read the request body to look for the To-Do _title_ and _dueDate_.

Here we need the `body-parser` module to accept and parse JSON request body. Nowadays, the `body-parser` package comes by default with Express and we just have to `require` it:

```js
const bodyParser = require('body-parser');
const bodyParser = require("body-parser");
app.use(bodyParser.json());
```

Next, inside the `create` TO-DO route, we will use the `.create()` method from **Sequelize**, to insert a *todo* into the database, based on the request body:

Next, inside the `create` TO-DO route, we will use the `.create()` method from **Sequelize**, to insert a _todo_ into the database, based on the request body:

```js
app.post('/todos', async function (request, response) {
console.log('Creating new Todo: ', request.body)
try {
const todo = await Todo.create({ title: request.body.title, dueDate: request.body.dueDate, completed: false })
return response.json(todo);
} catch (error) {
console.log(error)
return response.status(422).json(error);
}
})
```

app.post("/todos", async function (request, response) {
console.log("Creating new Todo: ", request.body);
try {
const todo = await Todo.create({
title: request.body.title,
dueDate: request.body.dueDate,
completed: false,
});
return response.json(todo);
} catch (error) {
console.log(error);
return response.status(422).json(error);
}
});
```

To test it out, first we have to make sure that the server is running:

```
node index.js
```

Then we will send a simple `curl` request from our terminal:
````

```
curl -d '{"title":"Go the gym","dueDate":"2022-07-02"}' -H "Content-Type: application/json" -X POST http://localhost:3000/todos
````
```

This `curl` call will create a new **todo** entry in our database, and will return the new database object to us.

We can further refractor the code by defining a `addTodo` class method in the `Todo` model, and moving the `Todo.create` method there itself.

We can further refractor the code by defining a `addTodo` class method in the `Todo` model, and moving the `Todo.create` method there itself.

```js
class Todo extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}

static addTodo({ title, dueDate }) {
return this.create({ title: title, dueDate: dueDate, completed: false });
}
class Todo extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}

static addTodo({ title, dueDate }) {
return this.create({ title: title, dueDate: dueDate, completed: false });
}
}
```

Here, inside the `addTodo` method, `this` refers to the class Todo itself.

Now we can call this class method `addTodo` from our route definition:

```js
app.post('/todos', async function (request, response) {
console.log('Creating new Todo: ', request.body)
app.post("/todos", async function (request, response) {
console.log("Creating new Todo: ", request.body);
try {
const todo = await Todo.addTodo(request.body);
return response.json(todo);
return response.json(todo);
} catch (error) {
console.log(error)
return response.status(422).json(error);
console.log(error);
return response.status(422).json(error);
}
})
});
```

### Step 4: Complete the `markAsCompleted Todo` endpoint implementation
To update the TO-DO that we've just created, we will use the `.update()` method of Sequelize.

To update the TO-DO that we've just created, we will use the `.update()` method of Sequelize.

But first, we have to find out the Todo that we want to update. In that case, we will use the `findByPk` method, where we have to pass the Todo ID that we are getting as part of the query parameter.

```js
app.put('/todos/:id/markAsCompleted', async function (request, response) {
console.log('We have to update a Todo with ID: ', request.params.id)
const todo = await Todo.findByPk(request.params.id)
})
app.put("/todos/:id/markAsCompleted", async function (request, response) {
console.log("We have to update a Todo with ID: ", request.params.id);
const todo = await Todo.findByPk(request.params.id);
});
```

Next, we will define an instance method in Todo model named `markAsCompleted`, where we will actually update the Todo using `.update()`

```js
class Todo extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}

static addTodo({ title, dueDate }) {
return this.create({ title, dueDate, completed: false });
}

markAsCompleted() {
return this.update({ completed: true })
}
class Todo extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}

static addTodo({ title, dueDate }) {
return this.create({ title, dueDate, completed: false });
}

markAsCompleted() {
return this.update({ completed: true });
}
}
```

Here, inside the `markAsCompleted` method, `this` refers to an instance of class Todo. Now we can call this method from our route definition.

```js
app.put('/todos/:id/markAsCompleted', async function (request, response) {
console.log('We have to update a Todo with ID: ', request.params.id)
const todo = await Todo.findByPk(request.params.id)
app.put("/todos/:id/markAsCompleted", async function (request, response) {
console.log("We have to update a Todo with ID: ", request.params.id);
const todo = await Todo.findByPk(request.params.id);
try {
const updatedTodo = await todo.markAsCompleted()
const updatedTodo = await todo.markAsCompleted();
return response.json(updatedTodo);
} catch (error) {
console.log(error)
return response.status(422).json(error);
console.log(error);
return response.status(422).json(error);
}
})
});
```

Let's test it out using `curl`:
````

```
curl -d '' -H "Content-Type: application/json" -X PUT http://localhost:3000/todos/1/markAsCompleted
````
```

Great! This request updates the to-do with *ID 1* and sets `completed` as `true`.

That's all for this video, see you in the next one.
Great! This request updates the to-do with _ID 1_ and sets `completed` as `true`.

That's all for this video, see you in the next one.
9 changes: 5 additions & 4 deletions backend-dev-with-express/milestone-test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
## Milestone Evaluation Specs

1. Validate the `GET /todos` endpoint whether it's returning list of all todos in JSON format or not.
The sample output will be something like this:
The sample output will be something like this:

```json
[
{
Expand All @@ -22,8 +23,8 @@ The sample output will be something like this:
"createdAt": "2022-08-01T09:50:55.759Z",
"updatedAt": "2022-08-01T09:50:55.759Z"
}
]
]
```

2. Validate the `DELETE /todos/:id` endpoint whether it's deleting a specific To-Do by it's ID or not. After successful deletion, the endpoint should return `true` or `false`. To cross check, you can call the `GET /todos/:id` API with the To-Do ID that we've just deleted. If deletion functionality implemented properly, this (`GET /todos/:id`) endpint should return `404`
3. Validate the Jest file written for testing the `DELETE /todos/:id` endpoint.
2. Validate the `DELETE /todos/:id` endpoint whether it's deleting a specific To-Do by it's ID or not. After successful deletion, the endpoint should return `true` or `false`. To cross check, you can call the `GET /todos/:id` API with the To-Do ID that we've just deleted. If deletion functionality implemented properly, this (`GET /todos/:id`) endpoint should return `404`
3. Validate the Jest file written for testing the `DELETE /todos/:id` endpoint.
Loading