GraphQL로 파일 업로드하기
1. grpahql-upload 설치하기
Graphql로 파일 업로드를 하기 위해선 Upload라는 Scalar Type을 다룰 수 있게 돕는 graphql-upload 을 npm으로 설치해야한다. 그러나 Typescript를 쓰는 분들은 아래와 같은 에러를 많이 접할 것이고 고치고 쓰는 분들도 있겠지만 나는 버전 충돌과 현재 설치된 다른 모듈들에도 영향을 주기 때문에 grpahql-upload-ts를 설치했다. 아래 두 가지 경우에 대해 링크를 첨부하니 본인에게 맞는 방법으로 설치해보자!
1-1. graphql-upload-ts 설치
https://www.npmjs.com/package/graphql-upload-ts?activeTab=readme#type-fileupload
1-2 grpahql-upload js 설정 방법
2. Resolver에 Upload Scalar Type추가하기
GraphQLUpload를 resolver에 추가해준다. 추가되었는지 확인하려면 console.log(resolvers)를 해보면 알 수 있다.
import { loadSchema } from '@graphql-tools/load';
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
import { makeExecutableSchema } from '@graphql-tools/schema';
import resolverMap from '../resolver';
import { GraphQLSchema } from 'graphql';
import { GraphQLUpload } from "graphql-upload-ts";
export default async function loadAllSchema() : Promise<GraphQLSchema> {
const typeDefs = await loadSchema('src/**/*.graphql', {
loaders: [new GraphQLFileLoader()]
});
var resolvers = resolverMap;
if (resolvers && !resolvers.Upload) {
resolvers.Upload = GraphQLUpload;
}
const schema: GraphQLSchema = makeExecutableSchema({
typeDefs : typeDefs,
resolvers,
});
return schema;
}
3. Schema에 Type 추가 및 Mutation에 추가하기
Upload를 scalar type으로 추가하고 복수로 주고받을 수 있도록 input type도 추가해놓는다. 그리고 사이트에서 제공한 File Type도 추가했다.
https://www.apollographql.com/docs/apollo-server/v2/data/file-uploads/
scalar Upload
input UploadFileListInput {
fileList: [Upload!]!
}
type File {
filename: String
mimetype: String
encoding: String
}
4. Image 다루는 Controller/Resolver 추가하기
createReadStream으로 이미지 데이터를 받은 후 읽어들여서 Buffer에 담아 binary형태로 DB에 저장했다. 본인은 mssql을 이용했기 때문에 varbinary(max) type으로 8MB 까지 처리가 가능하다. FileUpload라는 타입을 통해 파일을 받을 수있는 createReadStream, 파일명인 filename, 파일 타입인 mimetype으로 파일 정보를 주고받을 수 있다.
/**
* 이미지 등록하기
* @param args 새 정보
* @returns 성공 시 True, 새 이미지 정보. 실패 시 False
*/
const insertImageItem = async (args : any) => {
const { createReadStream, filename, mimetype } = await args.file as FileUpload;
await new Promise(async (resolve, reject) => {
const readStream = createReadStream();
var bufs : Uint8Array[] = [];
readStream.on('data', (chunk : Uint8Array) => {
bufs.push(chunk);
});
// 파일 읽기 완료 이벤트 리스너 사용 : reatream.on('end')
readStream.on('end', async () => {
const newImage : ImageDto = {
member_id: args.member_id,
image_type: args.image_type,
file: Buffer.concat(bufs),
}
try {
const image : Image = await Image.create(newImage);
return {res : true, msg : `Created image ${image.id}.`, data : [image]};
} catch(error) {
return {res : false, msg : error};
}
});
// 에러 발생 시 이벤트 리스너 사용 : reatream.on('error')
readStream.on('error', (err : string) => {
console.log('error:', err);
});
});
}
작성된 Controller를 아래와 같이 resolver랑 연결시키고 mutation에 등록시키면 끝난다.
const createImage = async (_: void, args:any) => {
return await Image.insertImageItem(args);
};
Schema에 연결
type Mutation {
#Image
createImage(member_id: Int! image_type: String! file: Upload!): ImageResponse!
updateImage(id:Int! image_type:String file:Upload): ImageResponse!
}
이번 삽질은 원하는 바를 얻기까지 좀 오래걸렸는데 다음에 대용량으로 파일을 주고받을때 stream을 어떤식으로 이용할지 옵션을 잘 보고 짜야겠다.
생각보다 file upload에 대한 정보가 많이 없어서 ㅠ 나와 같은 고민을 하신 분들께 많은 도움이 되었으면 좋겠다.
'개발 Study > GraphQL' 카테고리의 다른 글
[GraphQL] GraphQL 사용법 - (4) ThunderClient로 API 테스트하기 (0) | 2022.10.04 |
---|---|
[GraphQL] GraphQL 사용법 - (3) Sequelize 사용하기(1:1, ForeignKey, Join) (1) | 2022.09.30 |
[GraphQL] GraphQL 사용법 - (2) Sequelize + MSSQL 연동 (1) | 2022.09.29 |
[GraphQL] GraphQL 사용법 - (1) Schema 생성 후 ApolloServer 연동하기 (2) | 2022.09.27 |
[GraphQL] GraphQL과 REST (2) | 2022.09.21 |
댓글