티스토리 뷰

728x90
반응형

Step 01- apollo-server-express 설치


npm install apollo-server-express //설치

Step 02- Mutation중 editProfile() 메서드를 사용하는 경우 avatar를 Upload type으로 선언

  • Upload type으로 선언하게 된다면 첨부파일을 업로드할 수 있습니다.

 

Step 03- Mutation에서 editProfile()을 사용하면 resolverFn function이 실행됩니다.

  • 스트림(Stream)을 사용하여 파일 업로드를 합니다.

스트림이란?

- 스트림은 배열이나 문자열같은 데이터 컬렉션입니다. 스트림은 대용량의 파일을 다룰 때나 외부 소스로부터 데이터를 한번에 일부분씩 가져올때 사용됩니다.

 

스트림이 필요한 이유

- fs 모듈을 사용하면 파일을 읽고 쓸 수 있습니다. 그러나 파일이 대용량인 경우 파일 전체를 업로드 하기전에 메모리 버퍼를 절약하기 위해 뭔가를 해야할 상황이 발생할 수 있습니다. 그래서 파일의 일부분씩만 가져올 때 Stream을 사용합니다.

 

쓰기 스트림: createWriteStream

- 인터넷에서 파일을 요청하고 데이터의 일부를 받을 때마다 파일에 쓰는 것입니다.

 

pipe

- pipe는 입력을 출력으로 리다이렉트 할 수 있도록 해주는 또 다른 개념입니다. 

- pipe는 stream간에 read와 write 이벤트들을 연결해주기 때문에 여러 개의 pipe를 서로 연결할 수 있습니다.

 

결론

- 나의 workspace경로에 uploads폴더 내부에 파일을 업로드하는 것입니다.

- DB에는 이미지를 업로드하는게 아닌 이미지 경로만 업로드를 합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import fs from "fs"
import client from "../../client"
import bcrypt from "bcrypt"
 
const resolverFn = async (_, {
    firstName, lastName, username, email, password: newPassword, bio, avatar
}, { loggedInUser }) => {
 
    let avatarUrl = null;
    
    // 서버에 파일 업로드 시작 
    if(avatar){
        const { filename, createReadStream } = await avatar;
        const newFilename = `${loggedInUser.id}-${Date.now()}-${filename}`;
        const readsStream = createReadStream();
        const writeStream = fs.createWriteStream(process.cwd() + "/uploads/" + newFilename);
        readsStream.pipe(writeStream);
        avatarUrl = `http://localhost:4000/static/${newFilename}`;
    }
    // 서버에 파일 업로드 끝
 
    let tempPassword = null;
    if(newPassword){
        tempPassword = await bcrypt.hash(newPassword, 10);
    }
    const result = await client.user.update({
        where:{
            id:loggedInUser.id
        },
        data:{
            firstName,
            lastName,
            username,
            email,
            bio,
            ...(avatarUrl && {avatar:avatarUrl}),
            ...(tempPassword && {password:tempPassword})
        }
    })
 
    if(result.id){
        return{
            result: true
        }
    }else{
        return {
            result: false,
            error: "실패"
        }
    }
}
 
export default {
    Mutation: {
       editProfile: resolverFn
    }
}
cs

Step 04 - server.js에서 외부에서 이미지 url에 접근할 수 있도록 express.static사용

  • 업로드한 이미지의 url에 접근할 수 있도록 express.static을 사용하여 접근할 수 있도록 해줍니다.

ex) http://localhost:4000/static/3-1620806264766-dc7a3b17f90bdee8013630206b6dee08_thumb.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
require('dotenv').config();
import express from "express"
import { ApolloServer } from "apollo-server-express";
import { typeDefs, resolvers } from "./schema";
import { getUser } from "./users/users.utils";
 
const PORT = process.env.PORT;
 
const apollo = new ApolloServer({
    typeDefs,
    resolvers,
    context: async ({ req }) => {
        return {
            loggedInUser: await getUser(req.headers.token)
        }
    }
});
 
const app = express();
app.use("/static", express.static("uploads")); //upload 폴더를 인터넷에 올림
 
apollo.applyMiddleware({ app });
 
app.listen({ port: PORT }, () => {
        console.log(`Server is running on http://localhost:${PORT}/graphql`);
    });
 
 
cs

 

Step 05 - 업로드 결과 화면

  • 아래 사진에서 bio의 값은 super 123123으로 할당하고 avatar에는 이미지파일을 선택하여 업로드합니다.
  • DB에 bio값과 avatar값에 데이터가 삽입된것을 확인 할 수 있습니다.

 

파일 업로드 시 node 12 버전 이상에서 버그 발생경우 아래 url 참고

kdg-is.tistory.com/117

 

React - node - 12 이상에서 파일 업로드 버그

react에서 파일 업로드를 할 경우 node의 버전이 12 이상일 경우 아래 사진과 같은 버그가 발생할 수 도 있습니다. Step 01: package.json에 resolutions 추가 "resolutions": { "fs-capacitor": "^6.2.0", "grap..

kdg-is.tistory.com

 

728x90
반응형