초기 환경설정이 워낙 복잡하고 할게 하도 많아서 삭제하고 다시 만들기를 몇번이나 했는지.. 또 삭제하고 다시 만들 가능성이 있기에 작업순서를 간단하게 정리해보았다.
req.params, req.body
링크
깃허브 클론하기
폴더 만들기 : mkdir 내이름
폴더 들어가기 : cd 내이름
package.json 만들기 : npm init -y
package.json에서 내용 넣기
express 설치하기
npm install express
npm install -g nodemon
npm install --save-dev nodemon
npm install dotenv
npm install morgan
npm install typeorm
npm install mysql
npm install -g mysql
touch app.js
touch .env
touch .env.sample
touch .gitignore
CREATE DATABASE 데이터베이스명
으로 생성해둘 것!DATABASE_URL = "mysql://계정명:비밀번호@127.0.0.1:3306/데이터베이스명"
PORT = 포트번호
TYPEORM_CONNECTION = mysql
TYPEORM_HOST = 127.0.0.1
TYPEORM_USERNAME = 계정명
TYPEORM_PASSWORD = 비밀번호
TYPEORM_DATABASE = 데이터베이스명
TYPEORM_PORT = 3306
TYPEORM_LOGGING = TRUE
DATABASE_URL = URL
PORT = YOUR PORT NUMBER
TYPEORM_CONNECTION = mysql
TYPEORM_HOST = 127.0.0.1
TYPEORM_USERNAME = username
TYPEORM_PASSWORD = myPassword
TYPEORM_DATABASE = myDatabase
TYPEORM_PORT = 3306
TYPEORM_LOGGING = TRUE
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,dotenv
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,dotenv
/db/schema.sql
### dotenv ###
.env
...
npm start
로 app.js 동작 확인하기
mkdir db
npm install -g dbmate
dbmate new create_users_table
dbmate new create_posts_table
dbmate new create_likes_table
dbmate new create_comments_table
-- migrate:up
CREATE TABLE users
(
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(200) NOT NULL,
profile_image VARCHAR(1000) NULL,
password VARCHAR(200) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
-- migrate:down
DROP TABLE users;
-- migrate:up
CREATE TABLE posts
(
id INT NOT NULL AUTO_INCREMENT,
title VARCHAR(100) NOT NULL,
content VARCHAR(3000) NULL,
image_url VARCHAR(1000) NULL,
user_id INT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);
-- migrate:down
DROP TABLE posts;
-- migrate:up
CREATE TABLE likes
(
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
post_id INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (post_id) REFERENCES posts (id)
);
-- migrate:down
DROP TABLE likes;
-- migrate:up
CREATE TABLE comments
(
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
post_id INT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (post_id) REFERENCES posts (id)
);
-- migrate:down
DROP TABLE comments;
dbmate up
git branch 내이름/assignment1
git checkout 내이름/assignment1
git add .
git commit -m "[39기 내이름] Assignment 1: Express API - 초기환경세팅"
git push origin 내이름/assignment1
데이터베이스에 미리 데이터 입력하기
INSERT INTO users (name, email, profile_image, password, created_at, updated_at) VALUES ("Rebekah", "Glover12345@email.com", "https://github.com/amacneil/dbmate#command-line-options", "password", "2022-07-16 14:15:21", NULL);
INSERT INTO users (name, email, profile_image, password, created_at, updated_at) VALUES ("Fabian", "O'Connell12345@email.com", "https://github.com/amacneil/dbmate#command-line-options", "password1", "2022-07-16 14:15:21", NULL);
INSERT INTO users (name, email, profile_image, password, created_at, updated_at) VALUES ("Elenor", "Skiles12345@email.com", "https://github.com/amacneil/dbmate#command-line-options", "password2", "2022-07-16 14:15:21", NULL);
INSERT INTO users (name, email, profile_image, password, created_at, updated_at) VALUES ("Madge", "Quitzon12345@email.com", "https://github.com/amacneil/dbmate#command-line-options", "password3", "2022-07-16 14:15:21", NULL);
INSERT INTO posts (title, content, user_id, created_at, updated_at) VALUES ("위코드 1일차", "HTML과 CSS 익숙해지기..", 1, "2022-04-10 11:41:36", "2022-04-23 11:21:44");
INSERT INTO posts (title, content, user_id, created_at, updated_at) VALUES ("위코드 2일차", "Javascript 기본 문법 학습..", 1, "2022-04-10 11:41:36", "2022-04-23 11:21:54");
INSERT INTO posts (title, content, user_id, created_at, updated_at) VALUES ("위코드 3일차", "웹서비스의 역사와 발전 세션을 듣고..", 1, "2022-04-10 11:41:36", "2022-04-23 11:22:01");
INSERT INTO posts (title, content, user_id, created_at, updated_at) VALUES ("자료구조 1번", "BigO Notation이란 무엇인가?", 2, "2022-04-10 11:41:36", "2022-04-23 11:22:13");
INSERT INTO posts (title, content, user_id, created_at, updated_at) VALUES ("자료구조 2번", "시간 복잡도와 공간 복잡도에 대해서..", 2, "2022-04-22 14:12:45", NULL);
INSERT INTO posts (title, content, user_id, created_at, updated_at) VALUES ("프론트 개발 입문", "프론트 입문 HTML이란 무엇인가?", 3, "2022-04-23 11:43:25", "2022-04-23 11:56:25");
ALTER TABLE likes ADD created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
INSERT INTO likes (user_id, post_id, created_at) VALUES (1, 3, "2022-07-16 14:18:26");
INSERT INTO likes (user_id, post_id, created_at) VALUES (2, 3, "2022-07-16 14:18:26");
INSERT INTO likes (user_id, post_id, created_at) VALUES (3, 3, "2022-07-16 14:18:26");
INSERT INTO likes (user_id, post_id, created_at) VALUES (4, 3, "2022-07-16 14:18:26");
INSERT INTO likes (user_id, post_id, created_at) VALUES (3, 5, "2022-07-16 14:18:47");
INSERT INTO likes (user_id, post_id, created_at) VALUES (1, 6, "2022-07-16 14:18:47");
http 통신을 이용하여, 한 명 이상의 유저를 회원가입 해봅니다. Express 를 이용해 가상의 Westagram 서비스에 회원가입을 완료해주세요. 이 때 별도의 모듈화 없이 하나의 파일 (app.js) 에서 모든 코드를 작성합니다.
- 회원가입 API
- 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요.
- 알맞은 http 메소드를 선정하여서 유저의 정보를 백엔드 서버에 전달해주세요.
- 데이터가 생성됬을 때에 알맞는 http 상태코드를 반환해주세요.
- 데이터가 잘 db에 저장되었는지 여부를 테이블 스크린샷을 찍어서 PR에 같이 첨부하여 올려주세요.
- http response로 반환하는 JSON 데이터의 형태는 다음과 같습니다.
{ "message" : "userCreated" }
소스코드
app.post("/users/signup", async(req, res, next) => {
const { name, email, profileImage, password } = req.body
await appDataSource.query(
`INSERT INTO users(
name,
email,
profile_image,
password
) VALUES (?, ?, ?, ?);
`, [name, email, profileImage, password]
);
res.status(201).json({ message : "userCreated"});
})
httpie로 유저 회원가입 실행하기
postman으로 유저 회원가입 실행하기
mysql 확인하기
select * from users;
http 통신을 이용하여, 두 건 이상의 게시글을 등록해봅니다. 이 때 앞서 작성하였던 파일 (app.js) 에서 이어서 코드를 작성합니다.
- 게시글 등록 API
알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요.
- 알맞은 http 메소드를 선정하여서 게시글 내용 및 유저의 id 값을 백엔드 서버에 전달해주세요.
- 데이터가 생성됬을 때에 알맞는 http 상태코드를 반환해주세요.
- 데이터가 잘 db에 저장되었는지 여부를 테이블 스크린샷을 찍어서 PR에 같이 첨부하여 올려주세요.
- http response로 반환하는 JSON 데이터의 형태는 다음과 같습니다.
{ "message" : "postCreated" }
소스코드
app.post("/posts/signup", async(req, res, next) => {
const { title, content, imageUrl, userId } = req.body;
await appDataSource.query(
`INSERT INTO posts(
title,
content,
image_url,
user_id
) VALUES ( ?, ?, ?, ? );
`, [title, content, imageUrl, userId]
);
res.status(201).json({ message : "postCreated"});
})
httpie로 게시물 등록 실행하기
http -v POST 127.0.0.1:3000/posts/signup title="test_title1" content="test_content1" imageUrl="https://namu.wiki/jump/gZ1Bu4niCcY0xiLce31zTqT8LpUTWUhyabiB59f4C0FEYW%2BNyojDoZr2PobTX8fn%2BwSmxsXmp1ZOuxLkYk3%2Btw%3D%3D" userId:=4
postman으로 게시물 등록 실행하기
mysql 확인하기
http 통신을 이용하여, 게시글 전체 리스트를 불러와봅니다. 이 때 앞서 작성하였던 파일 (app.js) 에서 이어서 코드를 작성합니다.
- 게시글 리스트 불러오기 API
- 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요.
- 데이터가 호출될 때의 알맞는 http 상태코드를 반환해주세요.
- http response로 반환하는 데이터의 형태는 다음과 같습니다.
{ "data" : [ { "userId" : 1, "userProfileImage" : "userProfileImage1", "postingId" : 1, "postingImageUrl" : "imageUrlSample1", "postingContent" : "sampleContent1" }, { "userId" : 2, "userProfileImage" : "userProfileImage2", "postingId" : 2, "postingImageUrl" : "imageUrlSample2", "postingContent" : "sampleContent2" }, { "userId" : 3, "userProfileImage" : "userProfileImage3", "postingId" : 3, "postingImageUrl" : "imageUrlSample3", "postingContent" : "sampleContent3" }, { "userId" : 4, "userProfileImage" : "userProfileImage4", "postingId" : 4, "postingImageUrl" : "imageUrlSample4", "postingContent" : "sampleContent4" } ] }
소스코드
app.get("/posts/lookup", async(req, res, next) => {
await appDataSource.manager.query(
`SELECT
users.id as userId,
users.profile_image as userProfileImage,
posts.id as postingId,
posts.image_url as postingImageUrl,
posts.content as postingContent
FROM users
INNER JOIN posts
ON users.id = posts.user_id
`, (err, rows) => {
res.status(200).json({ "data" : rows });
});
})
httpie로 게시글 전체 리스트 불러오기 실행하기
http -v GET 127.0.0.1:3000/posts/lookup
postman으로 게시글 전체 리스트 불러오기 실행하기
mysql 확인하기
http 통신을 이용하여, 한명의 유저가 작성한 게시글을 불러옵니다. 이 때 앞서 작성하였던 파일 (app.js) 에서 이어서 코드를 작성합니다.
- 특정 유저가 작성한 게시글 상세 API
- 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요.
- 하나의 유저가 올린 여러개의 게시글을 보여주는 상세 페이지용 API를 작성해주세요.
- 데이터가 호출될 때에 알맞는 http 상태코드를 반환해주세요.
- Http response로 반환하는 데이터의 형태는 다음과 같습니다.
{ "data" : { "userId" : 1, "userProfileImage" : "userProfileImage1", "postings" : [ { "postingId" : 1, "postingImageUrl" : "postingImageUrlSample1", "postingContent" : "samplePostingContent1" }, { "postingId" : 2, "postingImageUrl" : "postingImageUrlSample2", "postingContent" : "samplePostingContent2" }, { "postingId" : 3, "postingImageUrl" : "postingImageUrlSample3", "postingContent" : "samplePostingContent3" } ] }
Today I Learn
console.log(rows) 를 실행한 결과, 배열안에 객체들로 이루어져있다는 걸 알았다! postings에는 아래 rows를 입력받아 userId, userProfileImage 라는 키를 삭제하는 함수를 만들고 그 반환값을 대입해주면 될 거 같다!
소스코드
app.get("/users/posts/lookup/:id", async(req, res, next) => {
const { id } = req.params;
await appDataSource.manager.query(
`SELECT
users.id as userId,
users.profile_image as userProfileImage,
posts.id as postingId,
posts.image_url as postingImageUrl,
posts.content as postingContent
FROM users
INNER JOIN posts
ON users.id = posts.user_id
WHERE users.id = ${id};
`,
(err, rows) => {
//console.log(rows);
let postings
res.status(200).json(
{ "data" : {
"userId" : rows[0].userId,
"userProfileImage" : rows[0].userProfileImage,
"postings" : postArr(rows)
}
});
});
})
userId, userProfileImage 키를 삭제해주는 함수를 선언:
const postArr = rows => {
for(let i=0; i<rows.length; i++){
delete rows[i].userId;
delete rows[i].userProfileImage;
}
return rows;
}
httpie로 유저가 작성한 게시글 상세 실행하기 (id=1인 유저)
postman으로 유저가 작성한 게시글 상세 확인하기 (id=1인 유저)
mysql 확인하기 (id=1인 유저)
http 통신을 이용하여, 게시글 전체 리스트와 상세 리스트를 불러와봅니다. 이 때 앞서 작성하였던 파일 (app.js) 에서 이어서 코드를 작성합니다.
- 게시글 정보 수정 엔드포인트 요구 사항
- 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요.
- 데이터베이스에 저장되어있는 1번 id 유저의 1번 id 게시글을 확인합니다. 이후 해당 내역의 content를 기존의 데이터와 다른 내용으로 수정하여 저장합니다.
- postingId가 1번인 게시물의 내용을 “기존과 다르게 수정한 내용입니다.”로 수정한다면, 데이터베이스에서 끌어와 http response로 반환하는 데이터의 형태는 다음과 같습니다.
{ "data" : { "userId" : 1, "userName" : "weCode", "postingId" : 1, "postingTitle" : "간단한 HTTP API 개발 시작!", "postingContent" : "기존과 다르게 수정한 내용입니다." } }
소스코드
app.patch("/posts/update/:userId/:postId", async(req, res, next) => {
const { userId, postId } = req.params;
const { content } = req.body;
await appDataSource.manager.query(
` UPDATE
posts
SET content=?
WHERE user_id=${userId} and id=${postId};
`, [content]
);
await appDataSource.manager.query(
`SELECT
users.id as userId,
users.name as userName,
posts.id as postingId,
posts.title as postingTitle,
posts.content as postingContent
FROM users
INNER JOIN posts
ON users.id = posts.user_id
WHERE users.id=${userId} and posts.id=${postId};
`, (err, rows) => {
console.log(rows)
res.status(200).json({"data" : rows});
});
})
httpie로 게시글 정보 수정 실행하기
mysql로 게시글 정보 수정 확인하기
Today I Learn
req.params 로 할당한 변수는 쿼리(`${변수명}`) 하면 되고
req.body 로 할당한 변수는 쿼리(`?`, [변수명]) 하면 된다영상자료에서 manager를 써도 동작되지만 가독성에 안 좋으므로 안 쓰는 방향으로 하라고 들었던 거 같다. 그래도 그냥 되니까 썼다.
http 통신을 이용하여, 한 건의 게시글을 삭제해봅니다. 이 때 앞서 작성하였던 파일 (app.js) 에서 이어서 코드를 작성합니다.
- 게시글 삭제 API
- 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요.
- 데이터가 삭제 될 때에 알맞는 http 상태코드를 반환해주세요.
- http response로 반환하는 JSON 데이터의 형태는 다음과 같습니다.
{ "message" : "postingDeleted" }
// #7 게시글 삭제 엔드포인트 구현
app.delete("/posts/delete/:id", async(req, res, next) => {
const { id } = req.params;
await appDataSource.query(
`DELETE
FROM posts
WHERE id=${id};
`, (err, rows) => {
res.status(204).end();
}
);
})
또는 상태코드 200일 때;
// #7 게시글 삭제 엔드포인트 구현
app.delete("/posts/delete/:id", async(req, res, next) => {
const { id } = req.params;
console.log(req.params);
await appDataSource.query(
`DELETE
FROM posts
WHERE id=${id};
`
);
res.status(200).json({ message : "postDeleted"});
})
httpie로 게시글 삭제 확인하기(postId=8)
또는
mysql 게시글 삭제 확인하기
Today I Learn
👉 상태코드 204 를 쓸 경우 res에 body를 담을 수 없어 json() 대신 end()를 쓴다고 한다. 멘토님이 204를 쓰는 것을 추천하셨지만 과제의 {"message" : "postingDeleted"} 를 반환하기 위해 200을 썼다.
http 통신을 이용하여, 한 건의 좋아요를 생성해봅니다. 이 때 앞서 작성하였던 파일 (app.js) 에서 이어서 코드를 작성합니다.
- 게시글 좋아요 누르기 API
- 알맞은 API 호출 URL을 설정하여서 클라이언트와(httpie/postman) 통신을 성공해주세요.
- 데이터가 생성 됬을 때 (좋아요가 눌렸을 때의) 알맞는 http 상태코드를 반환해주세요.
- http response로 반환하는 JSON 데이터의 형태는 다음과 같습니다.
{ "message" : "likeCreated" }
소스코드
app.post("/likes/:userId/:postId", async(req, res, next)=>{
const { userId, postId } = req.params;
await appDataSource.query(
`INSERT INTO likes(
user_id,
post_id
) VALUES (${userId}, ${postId});
` );
res.status(200).json({ message : "likeCreated" });
})
httpie로 게시글 좋아요 누르기 확인하기(userId=2 가 postId=1에 좋아요 누르기)
postman으로 게시글 좋아요 누르기 확인하기(userId=3 이 postId=1에 좋아요 누르기)
mysql 확인하기