묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
.next 파일 관련
aws ec2 인스턴스 하나에 프론트와 백을 동시에 실행시키려고 합니다 다만 프리티어 메모리 부족으로 npm run build를 로컬에서 빌드한 이후 .next 파일을 깃허브에 푸쉬해서 인스턴스에서 Pull받은 다음 npm start를 하려고 하는데 문제가 .next파일 용량이 커서 깃허브에 업로드가 안됩니다 lfs라는 방식으로 해결을 했지만 푸쉬를 할때마다 깃허브 무료 용량이 다 차는 바람에 쓰지 못하게 될것 같습니다 혹시 다른 방법이 있을까요? 그리고 프론트 서버에서 npm start를 했을때 next/prerender-manifest.json: unexpected token v in json at position 0 이런 에러가 나오는데 로컬에서 빌드하고 npm start했을때는 나오지 않던 에러여서 당황스럽네요 구글링도 해봤는데 해결하지 못했습니다 ㅜㅜ 혹시 방법이 있을까요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
이미지 업로드 시 data가 보내지지 않습니다..ㅠㅠ
안녕하세요. 강사님! 강의를 들으며 똑같이 작성했고 혹시 모를 오타가 있는지도 확인하면서 강사님 깃허브도 참조해보았는데 원인을 찾지 못하겠어서 문의드립니다. ㅠ ㅠ이미지 업로드를 하면 아래와 같이 오류가 뜨고 redux dev tools 로 확인해 보았을 때UPLOAD_IMAGES_REQUEST 만 처리되고 SUCCESS 로 넘어가지가 않아요.리퀘스트 되어 있는 데이터를 보면 빈 값인 것을 보니 데이터가 넘어가지 않는 것 같은데 도무지 원인을 모르겠습니다. 업로드를 하면 에러가 나면서 서버연결도 끊깁니다. ㅜㅜ제 코드에 뭐가 문제가 있는 건가요..?ㅠㅠ 확인 후 문제를 알려주시면 너무 감사할 것 같습니다..ㅠㅠㅠ[redux] import produce from "immer"; export const initialState = { mainPosts: [], // 이미지 업로드할 때 이미지의 경로들이 저장됨 imagePaths: [], uploadImagesLoading: false, uploadImagesDone: false, uploadImagesError: null, } export const UPLOAD_IMAGES_REQUEST = "UPLOAD_IMAGES_REQUEST"; export const UPLOAD_IMAGES_SUCCESS = "UPLOAD_IMAGES_SUCCESS"; export const UPLOAD_IMAGES_FAILURE = "UPLOAD_IMAGES_FAILURE"; const reducer = (state = initialState, action) => { return produce(state, (draft) => { switch (action.type) { case UPLOAD_IMAGES_REQUEST: draft.uploadImagesLoading = true; draft.uploadImagesDone = false; draft.uploadImagesError = null; break; case UPLOAD_IMAGES_SUCCESS: draft.imagePaths = action.data; draft.uploadImagesLoading = false; draft.uploadImagesDone = true; break; case UPLOAD_IMAGES_FAILURE: draft.uploadImagesLoading = false; draft.uploadImagesError = action.error; break; default: break; } }); }; export default reducer; [saga]import axios from "axios"; import { all, fork, put, takeLatest, throttle, call, } from "redux-saga/effects"; import { UPLOAD_IMAGES_FAILURE, UPLOAD_IMAGES_REQUEST, UPLOAD_IMAGES_SUCCESS, } from "../reducers/post"; function uploadImagesAPI(data) { return axios.post("/post/images", data); } function* uploadImages(action) { try { const result = yield call(uploadImagesAPI, action.data); yield put({ type: UPLOAD_IMAGES_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ type: UPLOAD_IMAGES_FAILURE, error: err.response.data, }); } } function* watchUploadImages() { yield takeLatest(UPLOAD_IMAGES_REQUEST, uploadImages); } export default function* postSaga() { yield all([ fork(watchUploadImages), ]); }[components] import React, { useCallback, useEffect, useRef } from "react"; import { useSelector, useDispatch } from "react-redux"; import { Form, Input, Button } from "antd"; import { UPLOAD_IMAGES_REQUEST, REMOVE_IMAGE, ADD_POST_REQUEST, } from "../reducers/post"; import useInput from "../hooks/useInput"; const PostForm = () => { const dispatch = useDispatch(); const { imagePaths, addPostDone } = useSelector((state) => state.post); const [text, onChangeText, setText] = useInput(""); const imageInput = useRef(); useEffect(() => { if (addPostDone) { setText(""); } }, [addPostDone]); const onSubmit = useCallback(() => { if (!text || !text.trim()) { return alert("게시글을 작성하세요."); } const formData = new FormData(); imagePaths.forEach((p) => { formData.append("image", p); }); formData.append("content", text); return dispatch({ type: ADD_POST_REQUEST, data: formData, }); }, [text, imagePaths]); const onClickImageUpload = useCallback(() => { imageInput.current.click(); }, [imageInput.current]); const onChangeImages = useCallback((e) => { console.log("images", e.target.files); const imageFormData = new FormData(); [].forEach.call(e.target.files, (f) => { imageFormData.append("image", f); }); dispatch({ type: UPLOAD_IMAGES_REQUEST, data: imageFormData, }); }, []); const onRemoveImage = useCallback( (index) => () => { dispatch({ type: REMOVE_IMAGE, data: index, }); }, [] ); return ( <Form style={{ margin: "10px 0 20px" }} encType="multipart/form-data" onFinish={onSubmit} > <Input.TextArea value={text} onChange={onChangeText} maxLength={140} placeholder="어떤 신기한 일이 있었나요?" /> <div> <input type="file" name="image" multiple hidden ref={imageInput} onChange={onChangeImages} /> <Button onClick={onClickImageUpload}>이미지 업로드</Button> <Button type="primary" style={{ float: "right" }} htmlType="submit"> 짹짹 </Button> </div> <div> {imagePaths?.map((v, i) => ( <div key={v} style={{ display: "inline-block" }}> <img src={`http://localhost:3065/${v}`} alt={v} style={{ width: "200px" }} /> <div> <Button onClick={onRemoveImage(i)}>제거</Button> </div> </div> ))} </div> </Form> ); }; export default PostForm; [back - routes/post.js]const express = require("express"); const multer = require("multer"); const path = require("path"); const fs = require("fs"); const { Post, Image, Comment, User } = require("../models"); const { isLoggedIn } = require("./middlewares"); const router = express.Router(); try { fs.accessSync("uploads"); } catch (error) { console.log("uploads 폴더가 없으므로 생성합니다."); fs.mkdirSync("uploads"); } const upload = multer({ storage: multer.diskStorage({ destination(req, file, done) { done(null, "uploads"); }, filename(req, file, done) { // amanda.png const ext = path.extname(file.originalname); // 확장자 추출(.png) const basename = path.basename(file.originalname, ext); // amanda done(null, basename + "_" + new Data().getTiem() + ext); // amanda15653484.png }, }), limits: { fileSize: 20 * 1024 * 1024 }, // 20MB }); router.post( "/images", isLoggedIn, upload.array("image"), // single , array , none async (req, res, next) => { // POST /post/images console.log(req.files); res.json(req.files.map((v) => v.filename)); } ); router.post("/", isLoggedIn, upload.none(), async (req, res) => { // POST /post try { const post = await Post.create({ content: req.body.content, UserId: req.user.id, }); if (req.body.image) { if (Array.isArray(req.body.image)) { // 이미지를 여러 개 올리면 image: [제로초.png, 부기초.png] const images = await Promise.all( req.body.image.map((image) => Image.create({ src: image })) ); await post.addImages(images); } else { // 이미지를 하나만 올리면 image: 제로초.png const image = await Image.create({ src: req.body.image }); await post.addImages(image); } } const fullPost = await Post.findOne({ where: { id: post.id }, include: [ { model: Image, }, { model: Comment, include: [ { model: User, // 댓글 작성자 attributes: ["id", "nickname"], }, ], }, { model: User, // 게시글 작성자 attributes: ["id", "nickname"], }, { model: User, // 좋아요 누른 사람 as: "Likers", attributes: ["id"], }, ], }); res.status(201).json(fullPost); } catch (error) { console.error(error); next(error); } }); module.exports = router;
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
post 에서 작성 후 mainPosts.map 에서 key={post.id} 가 undefined 로 나옵니다.
에러메세지:ADD_POST_SUCCESS 까지 잘 되었고 content 에 id 도 잘 들어가 있는걸로 보입니다. pages/index.jsimport React, { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import AppLayout from "../components/AppLayout"; import PostCard from "../components/PostCard"; import PostForm from "../components/postForm"; import { LOAD_POSTS_REQUEST } from "../reducers/post"; import { LOAD_USER_REQUEST } from "../reducers/user"; const Home = () => { const me = useSelector((state) => state.user.me); const { mainPosts, hasMorePosts, isLoadingPosts } = useSelector( (state) => state.post ); const dispatch = useDispatch(); useEffect(() => { dispatch({ type: LOAD_USER_REQUEST, }); dispatch({ type: LOAD_POSTS_REQUEST, }); }, []); useEffect(() => { function onScroll() { if ( window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300 ) { if (hasMorePosts && !isLoadingPosts) { dispatch({ type: LOAD_POSTS_REQUEST, }); } } } window.addEventListener("scroll", onScroll); return () => { window.removeEventListener("scroll", onScroll); }; }, []); return ( <AppLayout> {me && <PostForm />} {mainPosts.map((post) => ( <PostCard key={post.id} post={post} /> ))} </AppLayout> ); }; export default Home; reducers/post.jsimport produce from "immer"; export const initialState = { mainPosts: [], imagePaths: [], hasMorePosts: true, isAddingPost: false, isAddedPost: false, isAddPostErr: null, isRemovingPost: false, isRemovedPost: false, isRemovePostErr: null, isAddingComment: false, isAddedComment: false, isAddCommentErr: null, isRemovingComment: false, isRemovedComment: false, isRemoveCommentErr: null, isLoadingPosts: false, isLoadedPosts: false, isLoadPostsErr: null, }; export const LOAD_POSTS_REQUEST = "LOAD_POSTS_REQUEST"; export const LOAD_POSTS_SUCCESS = "LOAD_POSTS_SUCCESS"; export const LOAD_POSTS_FAILURE = "LOAD_POSTS_FAILURE"; export const ADD_POST_REQUEST = "ADD_POST_REQUEST"; export const ADD_POST_SUCCESS = "ADD_POST_SUCCESS"; export const ADD_POST_FAILURE = "ADD_POST_FAILURE"; export const REMOVE_POST_REQUEST = "REMOVE_POST_REQUEST"; export const REMOVE_POST_SUCCESS = "REMOVE_POST_SUCCESS"; export const REMOVE_POST_FAILURE = "REMOVE_POST_FAILURE"; export const ADD_COMMENT_REQUEST = "ADD_COMMENT_REQUEST"; export const ADD_COMMENT_SUCCESS = "ADD_COMMENT_SUCCESS"; export const ADD_COMMENT_FAILURE = "ADD_COMMENT_FAILURE"; export const addPost = (data) => ({ type: ADD_POST_REQUEST, data, }); const reducer = (state = initialState, action) => { return produce(state, (draft) => { switch (action.type) { case ADD_POST_REQUEST: draft.isAddingPost = true; draft.isAddedPost = false; draft.isAddPostErr = null; break; case ADD_POST_SUCCESS: draft.isAddingPost = false; draft.mainPosts.unshift(action.data); draft.isAddedPost = true; break; case ADD_POST_FAILURE: draft.isAddingPost = false; draft.isAddedPost = false; draft.isAddPostErr = action.error; break; case REMOVE_POST_REQUEST: draft.isRemovingPost = true; draft.isRemovedPost = false; draft.isRemovePostErr = null; break; case REMOVE_POST_SUCCESS: draft.isRemovingPost = false; draft.mainPosts = state.mainPosts.filter((v) => v.id !== action.data); draft.isRemovedPost = true; draft.isRemovePostErr = null; break; case REMOVE_POST_FAILURE: draft.isRemovingPost = false; draft.isRemovedPost = false; draft.isRemovePostErr = action.error; break; case ADD_COMMENT_REQUEST: draft.isAddingComment = true; draft.isAddedComment = false; draft.isAddCommentErr = null; break; case ADD_COMMENT_SUCCESS: draft.isAddingComment = false; const post = draft.mainPosts.find((v) => v.id === action.data.PostId); post.Comments.unshift(action.data); draft.isAddedComment = true; break; case ADD_COMMENT_FAILURE: draft.isAddingComment = false; draft.isAddedComment = false; draft.isAddCommentErr = action.error; break; case LOAD_POSTS_REQUEST: draft.isLoadingPosts = true; draft.isLoadedPosts = false; draft.isLoadPostsErr = null; break; case LOAD_POSTS_SUCCESS: draft.isLoadingPosts = false; draft.mainPosts = draft.mainPosts.concat(action.data); draft.isLoadedPosts = true; break; case LOAD_POSTS_FAILURE: draft.isLoadingPosts = false; draft.isLoadedPosts = false; draft.isLoadPostsErr = action.error; break; default: break; } }); }; export default reducer;sagas/post.jsimport { delay, all, fork, put, takeLatest, call } from "redux-saga/effects"; import axios from "axios"; import { ADD_POST_REQUEST, ADD_POST_SUCCESS, ADD_POST_FAILURE, ADD_COMMENT_FAILURE, ADD_COMMENT_SUCCESS, ADD_COMMENT_REQUEST, REMOVE_POST_REQUEST, REMOVE_POST_SUCCESS, REMOVE_POST_FAILURE, LOAD_POSTS_REQUEST, LOAD_POSTS_SUCCESS, LOAD_POSTS_FAILURE, } from "../reducers/post"; import { ADD_POST_TO_ME, REMOVE_POST_FROM_ME } from "../reducers/user"; function addPostAPI(data) { return axios.post( "/post", { content: data }, { withCredentials: true, } ); } function* addPost(action) { try { const result = yield call(addPostAPI, action.data); yield put({ type: ADD_POST_SUCCESS, content: result.data }); yield put({ type: ADD_POST_TO_ME, data: result.data.id, }); } catch (err) { console.log(err); yield put({ type: ADD_POST_FAILURE, error: err.response.data, }); } } function removePostAPI(data) { return axios.delete("/post", data); } function* removePost(action) { try { yield delay(1000); yield put({ type: REMOVE_POST_SUCCESS, data: action.data, }); yield put({ type: REMOVE_POST_FROM_ME, data: action.data, }); } catch (err) { yield put({ type: REMOVE_POST_FAILURE, error: err.response.data, }); } } function addCommentAPI(data) { return axios.post(`/post/${data.postId}/comment`, data); //POST /post/1/comment } function* addComment(action) { try { const result = yield call(addCommentAPI, action.data); yield put({ type: ADD_COMMENT_SUCCESS, data: result.data }); } catch (err) { console.log(err); yield put({ type: ADD_COMMENT_FAILURE, error: err, }); } } function loadPostsAPI() { return axios.get(`/posts`); } function* loadPosts(action) { try { const result = yield call(loadPostsAPI, action.data); yield put({ type: LOAD_POSTS_SUCCESS, data: result.data }); } catch (err) { console.log(err); yield put({ type: LOAD_POSTS_FAILURE, error: err.response.data, }); } } function* watchAddPost() { yield takeLatest(ADD_POST_REQUEST, addPost); } function* watchRemovePost() { yield takeLatest(REMOVE_POST_REQUEST, removePost); } function* watchAddComment() { yield takeLatest(ADD_COMMENT_REQUEST, addComment); } function* watchLoadPosts() { yield takeLatest(LOAD_POSTS_REQUEST, loadPosts); } export default function* postSaga() { yield all([ fork(watchAddPost), fork(watchRemovePost), fork(watchAddComment), fork(watchLoadPosts), ]); }routes/posts.jsconst express = require("express"); const { Post, Image, User, Comment } = require("../models"); const router = express.Router(); router.get("/", async (req, res, next) => { // GET /posts try { const posts = await Post.findAll({ limit: 10, order: [ ["createdAt", "DESC"], [Comment, "createdAt", "DESC"], ], include: [ { model: User, attributes: ["id", "nickname"], }, { model: Image, }, { model: Comment, include: [{ model: User, attributes: ["id", "nickname"] }], }, ], }); res.status(200).json(posts); } catch (err) { console.error(err); next(err); } }); module.exports = router; sql 테이블도 잘 들어가있고, 새로 고침 하면 포스팅은 잘 되어 있습니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
.next파일
로컬에서 Next를 빌드해서 aws 인스턴스에서 Npm start를 하려고 하는데 .next파일을 git에 푸쉬했을때 문제가 생기는 부분이 있을까요? 보안이라던지
-
미해결따라하며 배우는 TDD 개발 [2023.11 업데이트]
라우터를 돌릴 때
안녕하세요. 어제 알려주신 대로 제어판에서 다시 편집하고 npm run start까지 돌리는 것 까지는 잘 되었습니다. 근데 문제는 chrome에 localhost:5000을 쳤을 때는 잘 나왔지만 localhost:5000/api/products라고 칠 때는이렇게 뜹니다.이거는 단순한 코딩 문제인가요? 아니면 제가 잘 못따라 오고 있는건가요?그리고 MongoDB 새로 가입했을 때 제가 뭔가 실수한 거 같은데, MongoDB 쪽 스킵하고 Jest쪽만 들어도 상관없나요? 아니면 MongoDB도 순차적으로 들어야 하나요?
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
프론트서버를 s3로 배포하는 방식은 어떤가요?
강좌에서는 ec2 인스턴스 2개로 프론트 백엔드를 유지하는 방식인데 블로그 글들을 찾아보면 프론트서버는 s3로 유지하는 경우가 많더라구요. Get post patch delete 같은 요청에 열려있다는 단점은 있지만 프론트서버같은 정적인 컨텐츠에는 큰 무리가 없고 무엇보다 ec2 2개를 만드는것보다 과금이 없다는건데.. 실제 서비스를 운영할때는 어떤방식으로 하는 편인가요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
aws 포트지정
노드버드 프로젝트를 하나의 인스턴스에서 프론트와 백 서버 둘다 올리기 위해서aws 인스턴스 3000번 포트와 3065번 포트를 열어놓으려고 하는데 사용자지정tcp에서 열어놓으면 되는걸까요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
npm run build관련 질문
aws 한개의 인스턴스에 서버와 프론트 서버를 같이 사용하려고 하는데 프리티어에서는 next js의 num run build까지 하게 되면 서버가 터지는 걸로 알고 있습니다 해서 로컬에서 num run build를 해서 깃허브에 푸쉬한 이후 빌드된 파일을 인스턴스에서 Pull 받으려고 하는데 그러면 기존에 gitignore로 인해서 깃허브로 푸쉬가 안되고 있던 node_modules파일이랑 .next파일을 푸쉬해줘야 ec2에서 Pull을 받으면 빌드된게 반영되는건가요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
UpdateValuesMissingError
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm/repository/Repository'; import { User } from '../users/entities/user.entity'; import { Payment, POINT_TRANSACTION_STATUS_ENUM, } from './entities/payment.entity'; @Injectable() export class PaymentService { constructor( @InjectRepository(Payment) private readonly paymentRepository: Repository<Payment>, @InjectRepository(User) private readonly userRepository: Repository<User>, ) {} async create({ impUid, amount, currentUser }) { const pointTransaction = await this.paymentRepository.create({ impUid, amount, user: currentUser, status: POINT_TRANSACTION_STATUS_ENUM.PAYMENT, }); await this.paymentRepository.save(pointTransaction); const user = await this.userRepository.findOne({ id: currentUser.id }); console.log(amount); await this.userRepository.update( { id: user.id }, // where { point: user.point + amount }, ); return pointTransaction; } } payment 과제 중 payment.service.ts 코드입니다.결제는 문제없이 처리가 되었고, payment 테이블에 거래기록이 저장되어야 하는데 이러한 에러가 발생합니다.[Nest] 288 - 03/29/2023, 7:34:01 AM ERROR [ExceptionsHandler] Cannot perform update query because update values are not defined. Call "qb.set(...)" method to specify updated values. 여러 시도를 해봤지만 해결되지 않아 커뮤니티에 글 남깁니다!
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
react-query 적용
제로초쌤 혹시 swr 대신에 react-query로 적용한 버젼을 따로 강의해주시거나 그럴 의향있으신가요!? swr은 slack 강좌랑 nodebird 강좌를 통해서 감을 잡아가고 있는데 react-query 는 공식문서를 보면서도 반밖에 잘 이해가 안가서 어떻게 적용하는지 궁금합니다..!
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
왜 자기 게시글을 리트윗하는 것을 금지해야하는 지 궁금합니다.
왜 자기 게시글을 리트윗하는 것과자기게 시글을 남이 리트윗 한 거를 자기가 또 리트윗 하는 거를 금지해야하는 지 궁금합니다.실제 트위터에서 보면 제 트윗을 제가 또 리트윗 하는 것이 가능하던데 특별한 이유라도 있나요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
로그인 클릭시 로딩
안녕하세요 제로초님 saga와 reducer 연결하는 강의를 듣고 있는데 로그인 버튼 클릭시 로딩만 되고 다음으로 안 넘어가서 질문 드립니다..에러는 안 나고 리덕스 데브툴즈에는 LOG_IN_REQUEST만 뜨는 상태입니다.console창에서 reducer login은 뜨지만 saga logIn은 안 떠서 sagas/user의 function* login() {} 함수가 실행이 안되는 것 같습니다..index.jsuser/reduceruser/sagaconfigureStore.js아래에 해결한 사람들의 방법으로도 해봤는데 여전히 안되어서 질문 남깁니다...!!
-
해결됨이미지 관리 풀스택(feat. Node.js, React, MongoDB, AWS)
이미지 업로드 시 배열로
공부하던중 응용해보고 싶어서 업로드 하는 이미지들을 배열에 담아보려고 이런 스키마를 추가하여 여러가지 방법을 찾아가면서 시도를 해보다가 몇일째 진행이 안되어서 수업 내용에서는 벗어나지만 선생님께 도움 요청 드립니다 ㅠㅠ
-
미해결몽고DB + node express + ionic6 연동
몽고디비 연결이 안됩니다.
안녕하세요,몽고디비 연결이 안되서 검색하니까, uri 주소를 바꿔보라해서 아래처럼 했습니다.그런데, callback 함수가 실행이 전혀 안되네요...어떻게하면 좋을까요..? 검색하니 mongodb 4.0.0 버전을 깔아야하나보네요.. 라이브러리가 업데이트 되면서, 콜백 함수기능이 없어진거 같습니다. 수고하세요~!
-
미해결따라하며 배우는 TDD 개발 [2023.11 업데이트]
node.js에 대한 이상점
안녕하세요. 어제 강의에서 알려주신대로 node.js를 설치하고 npm init, npm install express mongoose --save, npm install jest supertest node-mocks-http --save-dev까지 설치해서 실행까지 했는데, 문제는 테스트를 실행할 때, 버전이 맞지 않는다고 테스크 결과 자체가 뜨지 않는다는 겁니다. 제가 현재 윈도우를 쓰고 있는데 강의하고 있는 컴터는 맥북이라 달라서 그런지 조금 헷갈립니다. 기존에 작업했던거 전부 삭제하고 다시 깔아야 하낭요? 일단 제가 node.js를 깔았을때 node_modules가 폴더 형식으로 뜨고, package.json은 빨간 문양이 뜹니다.
-
미해결Slack 클론 코딩[백엔드 with NestJS + TypeORM]
일반적인 ORM 사용패턴(DDL, DML) 문의
수업에서는 기존 DB라 typeorm-model-generator를 사용했는데요,저의 질문의 요점은 ORM으로 DML 위주의 사용이 보편적인가 하는 것입니다.제가 python하다가 node.js로 넘어와서, python 예를 들어 죄송합니다만,https://velog.io/@youngkiu/SQLAlchemy-with-DDLpython에서는 model도 create table sql로 만들지 않고, model을 생성하고, ORM에서 DDL 처리도 같이 해주었습니다.스프링에서도 DDL은 ORM을 사용하지 않고, DB에서 직접 처리한다는 이야기를 듣기도 하여,업계에서 ORM의 일반적인 사용방법이 궁금하여 질문드립니다.늘 많이 배우고 있습니다. 감사합니다.타입스크립트 책 얼릉 출간해 주세요. 바로 구매하겠습니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
unexpected end of input
console.log("안녕하세요, 문자 인증번호 보내드립니다.") function createTokenOfPhone(myphone){ if(myphone.length !== 10 && myphone.length !== 11){ console.log("에러 발생! 핸드폰 번호를 제대로 입력해 주세요. ") return } const aaaa=6 if(aaaa === undefined){ console.log("에러 발생!!! 갯수를 제대로 입력해 주세요!!!") return } else if(aaaa <= 0){ console.log("에러 발생!! 갯수가 너무 적습니다!!") return }else if(aaaa > 10){ console.log("에러 발생!!! 갯수가 너무 많습니다!!!") return } const result = String(Math.floor(Math.random() * 10 ** aaaa)).padStart(aaaa,"0") console.log(result) console.log(myphone+ "번호로 인증번호" +result+ "를 전송합니다!!!") createTokenOfPhone("01012341234") 수업과 동일하게 코드를 작성했으나 아래와 같은 에러가 뜹니다. (base) c@Dui-c-G9C7V6620L 01-01-token % node index.js/Users/c/Desktop/codecamp-backend-03./class/01-01-token/index.js:25createTokenOfPhone("01012341234") SyntaxError: Unexpected end of input at internalCompileFunction (node:internal/vm:73:18) at wrapSafe (node:internal/modules/cjs/loader:1176:20) at Module._compile (node:internal/modules/cjs/loader:1218:27) at Module._extensions..js (node:internal/modules/cjs/loader:1308:10) at Module.load (node:internal/modules/cjs/loader:1117:32) at Module._load (node:internal/modules/cjs/loader:958:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) at node:internal/main/run_main_module:23:47
-
미해결Express 튜토리얼 : 웹 서비스를 위한 핵심 API
mongoDB 어플리케이션 연결이 안됩니다...
```const express = require("express"); const MongoClient = require("mongodb").MongoClient; const app = express(); const port = 5000; const MongoURL = "mongodb+srv://username:비밀번호@cluster0.elhcowk.mongodb.net/express?retryWrites=true&w=majority"; var db, post; app.use(express.static("public")); app.use(express.urlencoded({ extended: false })); app.set("view engine", "ejs"); //app.set("view engine", "pug"); app.get("/", (req, res) => { post.insertOne({ 제목: "test", 내용: "test", 날짜: new Date(), }); res.render("index"); }); app.post("/calculator", (req, res) => { let result = Number(req.body.num1) + Number(req.body.num2); res.render("result", { result: result }); }); app.all("*", (req, res) => { res.status(404).send("찾을 수 없는 페이지입니다!"); }); MongoClient.connect(MongoURL, (err, database) => { if (err) { console.log(err); return; } else { app.listen(port, () => { console.log(`접속 완료됫어요 ${port}`); }); db = database.db("express"); post = db.collection("posts"); } }); ```강의 해주신대로 위 코드를 입력하고 nodemon을 실행하였음에도.. [nodemon] starting node index.js 라는 문구만 나올뿐.. db연동이 안됩니다 ㅠㅠ혹시 제 코드에 문제가 있나요..? url 부분에 username과 비밀번호는 제 몽고디비 아이디 비밀번호 입력했습니다..혹시 코드부분에서 잘못된 점이 있나요..?
-
해결됨[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
테스트 코드 깃헙
안녕하세요 혹시 테스트 코드나 service 코드는 깃헙에 따로 올라와있지는 않나요?https://github.com/ZeroCho/nodejs-book/tree/master/ch11/11.1/nodebird여기에는 안 보여서 질문합니다!
-
미해결탄탄한 백엔드 NestJS, 기초부터 심화까지
dto 와 entity의 유지보수
안녕하세요. 상석님! 상석님의 강의를 듣고 공식문서와 typeorm, mongoose등의 공식문서를 함께 이용하여 nest 프로젝트를 제작중인 1년차 node js 개발자입니다. 강의 너무 잘 들었습니다. 개인적으로 프로젝트를 진행하는 중 dto파일과 entity를 어떻게 관리하면 수월할까 라는 고민을 깊게 하게 되었습니다. chat gpt나 스택오버 플로우, 구글 등 많은 검색을 해봤지만 제 실력이 부족한지 정보를 찾기가 힘들어 여쭤보게 되었습니다. export class CreateRequestPostDto { @ApiProperty({ example: 'youtube uri', name: 'youtubeUri' }) @IsUrl() uri: string; @ApiProperty({ example: 'postTitle writed for user' }) @IsString() postTitle: string; @ApiProperty({ example: 'postDescription writed for user' }) @IsString() postDescription: string; } export class UpdatePostDto { @ApiProperty({ example: 'postTitle writed for user' }) @IsString() postTitle: string; @ApiProperty({ example: 'postDescription writed for user' }) @IsString() postDescription: string; }위는 제가 만들고 있는 프로젝트의 일부입니다. postTitle과 postDescription이 두 클래스에서 중복이 되는 케이스인데 상속을 이용해서 postTitle과 postDescription을 따로 빼는 방법은 제가 원하는 방향이 아닙니다.저는 기본적인 base dto클래스를 하나 만들어 놓고 이를 재활용하는 방법을 사용하고 싶습니다. export class BasePostClass { @ApiProperty({ example: 'youtube uri', name: 'youtubeUri' }) @IsUrl() uri: string; @ApiProperty({ example: 'postTitle writed for user' }) @IsString() postTitle: string; @ApiProperty({ example: 'postDescription writed for user' }) @IsString() postDescription: string; }만약 위와 같은 클래스가 있다면 이를 이용해서export class uriPostClass { uri: 위의 BasePostClass에 있는 uri 프로퍼티만을 가져와서 이 곳에서 사용하고 싶습니다. }이와 같이 @ApiProperty 데코레이터를 다시 적어주지 않아도 되고 BasePostClass의 프로퍼티 하나를 바꾸면 이 클래스를 이용해 다른 클래스들에 영향을 주고싶은겁니다.uri라는 이름을 URI로 변경하면 이 다른 클래스에서도 영향을 받아 URI로 변한다거나 하다못해 서버 실행 과정에서 에러라도 발생시킬 수 있도록 하고싶습니다.프로젝트가 커지다보니 DTO파일을 관리하기도 쉽지 않았어요. db의 컬럼 이름을 하나 바꿔주면 여기저기 dto파일을 찾아다니며 같이 바꿔줘야 했습니다. 좋은 방법이 있다면 알려주실 수 있을까요?