BE_westagram_다른 사람 코드 분석_TIL

송철진·2022년 11월 8일
0

Toy Project

목록 보기
5/10

잘하는 다른 사람의 코드를 보고 배우기

mysql2를 설치해야 JSON_arrayagg, JSON_OBJECT 구문을 쓸 수 있다!

npm install mysql2

과제1: health check

app.get("/ping", (req,res) => {
    res.json({ message : "pong" });
})

과제2: 유저 회원가입

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"});
})

과제3: 게시글 등록하기

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"});
})

오현상

app.post("/post", async (req, res, next) => {
  const { title, content, image_url, user_id } = req.body;
  await appDataSource.query(
    `
    INSERT INTO posts(
      title,
      content,
      image_url,
      user_id
    ) VALUES (?, ?, ?, ?);
    `,
    [title, content, image_url, user_id]
  );
  res.status(201).json({ message: "postCreated" });
});

한상엽

app.post('/posts', async (req, res) => {
    const { title, content, contentImage, userId } = req.body;

    try {
        await database.query(
            `INSERT INTO posts(
                title,
                content,
                content_image,
                user_id
            ) VALUES (?,?,?,?);
            `,
            [title, content, contentImage, userId]
        );
        return res.status(201).json({ message: 'post successfully created' });
    } catch (err) {
        if (err.sqlMessage.includes('foreign key constraint fails')) {
            return res.status(409).json({ error: 'no such user' });
        } else {
            return res.status(520).json({ error: 'unknown error' });
        }
    }
});

과제4: 모든 게시글 불러오기

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 });
        });
})

오현상

app.get("/posts", async (req, res) => {
  const posts = await appDataSource.query(
    `
        SELECT
          u.id as userId,
          u.profile_image as userProfileImage,
          p.user_id as postingId,
          p.image_url as postingImageUrl,
          p.content as postingContent
        FROM users u
        JOIN posts p ON u.id = p.user_id;
        `
  );
  res.status(200).json({ data: posts });
});

한상엽

app.get('/posts', async (req, res) => {
    await database.query(
        `SELECT
            users.id as userId,
            users.profile_image as userProfileImage,
            posts.id as postingId,
            posts.content_image as postingImageUrl,
            posts.content as postingContent
        FROM users
        INNER JOIN posts ON posts.user_id = users.id
        `,
        (err, posts) => {
            return res.status(200).json(posts);
        }
    );
});

과제5: 특정 유저가 작성한 게시글 불러오기

const postArr = rows => {
    for(let i=0; i<rows.length; i++){
        delete rows[i].userId;
        delete rows[i].userProfileImage;
    }
    return rows;
}

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) => { 
            res.status(200).json(
                { "data" : {
                        "userId" : rows[0].userId, 
                        "userProfileImage" : rows[0].userProfileImage,
                        "postings" : postArr(rows)
                    }
                });
        });
})

오현상

app.get("/userPost/:userId", async (req, res) => {
  const { userId } = req.params;
  const userPost = await appDataSource.query(
    `
    SELECT 
      users.id,
      users.profile_image,
        JSON_ARRAYAGG(
          JSON_OBJECT(
            "postingId",posts.id,
            "postingImageUrl", posts.image_url,
            "postingContent",posts.content
          )
        ) as postings
    FROM users
    LEFT JOIN posts ON users.id = posts.user_id
    WHERE users.id = ?
    GROUP BY users.id;
    `,
    [userId]
  );
  const result = userPost.map((userPost) => ({
    ...userPost,
    postings: JSON.parse(userPost.postings),
  }));
  res.status(200).json({ data: result });
});

2023.01.17 - map과 spread연산자와 JSON.parse로 구현한 이유는 mysql 버전 때문에 파싱이 안돼서 그랬다고 한다. 해당 이슈는 npm i -g mysql2로 해결했다고~

한상엽

app.get('/users/:userId/posts', async (req, res) => {
    const { userId } = req.params;

    try {
        const rows = await database.query(
            `SELECT
            users.id as userId,
            users.profile_image as userProfileImage,
            JSON_ARRAYAGG(
                JSON_OBJECT(
                    "postingId", posts.id,
                    "postingImageUrl", posts.content_image,
                    "postingContent", posts.content
                )
            ) as postings
            FROM
                posts
            JOIN users ON posts.user_id = users.id 
            WHERE user_id = ?
            GROUP BY posts.user_id;
            `,
            [userId]
        );

        return res.status(200).json({ data: rows });
    } catch (err) {
        return res.status(409).json({ error: 'invalid input' });
    }
});

과제6: 게시글 내용 수정하기

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) => { 
            res.status(200).json({"data" : rows});
    });
})

오현상

app.patch("/post/:postId", async (req, res, next) => {
  const { postId } = req.params;
  const { title, content, image_url } = req.body;
  const checkExisted = await appDataSource.query(
    `
      SELECT EXISTS
      (SELECT * FROM posts
      WHERE id = ?)
      AS postExist
      `,
    [postId]
  );
  if (checkExisted[0].postExist == 1) {
    await appDataSource.query(
      `
        UPDATE posts SET
          title = ?,
          content = ?,
          image_url = ?
        WHERE posts.id = ?
        `,
      [title, content, image_url, postId]
    );
  } else {
    res.status(404).json({ message: "Non Existing Post" });
  }
  const editedPost = await appDataSource.query(
    `
      SELECT
        users.id as userId,
        users.user_name as userName,
        posts.id as postingId,
        posts.title as postingTitle,
        posts.content as postingContent
      FROM users
      JOIN posts ON users.id = posts.user_id
      WHERE posts.id = ?
      `,
    [postId]
  );
  res.status(201).json({ data: editedPost });
});

한상엽

app.put('/posts', async (req, res) => {
    const { postingId, postingTitle, postingContent, postingImage } = req.body;
    try {
        await database.query(
            `UPDATE posts
                SET
                    title = ?,
                    content = ?,
                    content_image = ?
                    WHERE id = ?;
            `,
            [postingTitle, postingContent, postingImage, postingId]
        );
        const rows = await database.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 
            WHERE posts.id = ? AND posts.user_id=users.id;
            `,
            [postingId]
        );

        return res.status(200).json({ data: rows });
    } catch (err) {
        return res.status(409).json({ error: 'invalid input' });
    }
});

과제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();
        }
    );    
})

오현상

app.delete("/post/:userId", async (req, res, next) => {
  const userId = req.params.userId;
  const { postId } = req.body;
  const checkExisted = await appDataSource.query(
    `
      SELECT EXISTS
      (SELECT * FROM posts
      WHERE id = ?)
      AS postExist
      `,
    [postId]
  );
  if (checkExisted[0].postExist == 1) {
    await appDataSource.query(
      `
        DELETE
        FROM posts
        WHERE posts.user_id = ? and posts.id = ?
      `,
      [userId, postId]
    );
    res.status(200).json({ message: "postingDeleted" });
  } else {
    res.status(404).json({ message: "Non Existing Post" });
  }
});

한상엽

app.delete('/posts/:postId', async (req, res) => {
    const { postId } = req.params;
    await database.query(
        `DELETE FROM likes
        WHERE post_id = ?
        `,
        [postId]
    );
    await database.query(
        `DELETE FROM posts
		WHERE id = ?
		`,
        [postId]
    );
    return res.status(200).json({ message: 'successfully deleted' });
});

TIL_2022.01.17

그땐 단순히 게시글만 삭제하면 그만인 API과제라고 생각했는데
게시글이 삭제됐으니 그 게시글에 좋아요를 누른 정보도 사라져야 마땅하다.
불필요한 정보가 메모리를 차지하는 꼴이다

전 직장에서 NMS 소프트웨어를 시험 테스트할 때 유사한 경험이 있다
장비 목록이 있는 device table과 장비와 장비를 연결하는 link table이 있다.

  1. 장비A장비B링크1로 연결한다
  2. 장비B를 삭제한다
  3. 다시 장비B를 생성한다.

무슨 일이 생기는가? 이 때 장비의 IP주소가 pk다. 새로 생성한 장비임에도 불구하고 장비A의 IP주소와 장비B의 IP주소가 연결되어 있다는 링크1 정보가 link table에 남아있어서 링크1이 표출되었다. 이 후 개발자에게 요청하여 해당 이슈는 개선되었다

글자 그대로 API만 구현하면 완성~하고 끝나는 개발자가 아니라
제품이 어떻게 굴러가는가에 대해 그 다음을 생각하는 개발자가 되자.

과제8: 좋아요 누르기/취소하기

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" });
})

app.delete("/likeDelete/:userId/:postId", async(req, res, next)=>{
    const { userId, postId } = req.params;
    await appDataSource.query(
        `DELETE 
            FROM likes
            WHERE user_id=${userId} and post_id=${postId};`
        , (err, rows) => {
            res.status(200).json({ message : "likesDeleted" });
        }
    )
})

오현상

app.post("/likes", async (req, res, next) => {
  const { userId, postId } = req.body;

  const likes = await appDataSource.query(
    `
    SELECT EXISTS
    (SELECT * FROM likes
    WHERE user_id = ? and post_id = ?)
    AS 'LIKED';
    `,
    [userId, postId]
  );
  if (likes[0].LIKED == 0) {
    await appDataSource.query(
      `
        INSERT INTO likes(
          user_id,
          post_id
        ) VALUES (?,?);
        `,
      [userId, postId]
    );
    res.status(201).json({ message: "likeCreated" });
  } else {
    await appDataSource.query(
      `
        DELETE
        FROM likes
        WHERE user_id = ? and post_id = ?
      `,
      [userId, postId]
    );
    res.status(201).json({ message: "likesDeleted" });
  }
});

한상엽

app.post('/likes', async (req, res) => {
    const { userId, postId } = req.body;

    const rows = await database.query(
        `SELECT id,user_id,post_id
            FROM likes 
            WHERE user_id = ? AND post_id = ?;
        `,
        [userId, postId]
    );

    try {
        if (rows.length === 0) {
            await database.query(
                `INSERT INTO likes(
                    user_id,
                    post_id
                ) VALUES (?,?);
                `,
                [userId, postId]
            );
            return res.status(201).json({ message: 'like Created' });
        } else {
            throw 'already liked';
        }
    } catch (err) {
        if (err === 'already liked') {
            return res.status(409).json({ error: err });
        } else {
            return res.status(520).json({ error: 'Invalid input' });
        }
    }
});
profile
검색하고 기록하며 학습하는 백엔드 개발자

0개의 댓글