1. use Altair
![](https://velog.velcdn.com/images/jinyinshu/post/caef54fe-beb4-4e29-8b5f-5a243b260add/image.png)
![](https://velog.velcdn.com/images/jinyinshu/post/b2943f53-a1ae-460c-8e49-5249b8aced46/image.png)
2. shared/shared.utils.js
import AWS from 'aws-sdk'
AWS.config.update({
credentials: {
accessKeyId: process.env.AWS_KEY,
secretAccessKey: process.env.AWS_SECRET,
},
})
///기본 설정!! .env안에 AWS_KEY와 AWS_SECRET를 저장해 놓았음.
export const uploadToS3 = async (file, userId, folderName) => {
console.log(file)
///uploadToS3라는 component를 만들어서 uploadPhoto와 editProfile에서사용
/// ex)editProfile.resolver.js
////===> avatarUrl = await uploadToS3(avatar, loggedInUser.id, "avatars")
///ex)uploadPhoto.resolver.js
///const fileUrl = await uploadToS3(file, loggedInUser.id, "uploads")
///file: fileUrl
///반드시 console.log(file)을 찍어서 filename과 createReadStream 위치 확인할것
const {
filename, createReadStream
} = await file
///editProfile(avatar), uploadPhoto(file)로 부터 밭은 file에서
///filename과 createReadStream 위치 확인.
const readStream = createReadStream()
const objectName = `${folderName}/${userId}-${Date.now()}-${filename}`
///S3에 들어갈 filename을 만듬, filder도 지정해 줄 수 있음.
const { Location } = await new AWS.S3()
.upload({
Bucket: 'schoolgram',
///aws에서 만들었던 bucket의 name
Key: objectName,
///저장될 filename
ACL: 'public-read-write',
Body: readStream,
})
.promise()
console.log(Location)
return Location
///S3, bucket에 저장된 후 url을 return함.
///url은 Location에 저장되어 return됨.
/// uploadPhoto, editProfile에서 return 된 Location(url) 즉, url을 returl받음.
}
3. editProfile.resolver.js
import bcrypt from 'bcryptjs'
import prisma from '../../client'
import { protectedResolver } from '../users.util'
import fs from 'fs'
import { uploadToS3 } from '../../shared/shared.utils'
const resolveFn = async (
_,
{ username, email, password: newPassword, bio, avatar },
{ loggedInUser }
) => {
let avatarUrl = null
if (avatar) {
avatarUrl = await uploadToS3(avatar, loggedInUser.id, "avatars")
///avatar는 image File임, avatar, loggedInUser.id, 'avatars'(folder 이름)
///위 3개를 args로 shared.utils.js의 uploadToS3 component에 보냄.
///그리고 return으로 S3에 저장된 url을 return받아 avatarUrl에 저장함.
--------->server에 photo저장하기 위해서 밑의 code 참조.
// const {
// file: { filename, createReadStream },
// } = await avatar
// const newFilename = `${loggedInUser.id}-${Date.now()}-${filename}`
// const readStream = createReadStream()
// const writeStream = fs.createWriteStream(
// process.cwd() + '/uploads/' + newFilename
// )
// readStream.pipe(writeStream)
// avatarUrl = `http://localhost:4000/static/${newFilename}`
}
let uglyPassword = null
if (newPassword) {
uglyPassword = await bcrypt.hash(newPassword, 10)
}
console.log(loggedInUser)
const updatesUser = await prisma.user.update({
where: {
id: loggedInUser.id,
},
data: {
username,
email,
bio,
...(uglyPassword && { password: uglyPassword }),
...(avatarUrl && { avatar: avatarUrl }),
},
})
if (updatesUser.id) {
return {
ok: true,
}
} else {
return {
ok: false,
error: 'Could not update profile',
}
}
}
export default {
Mutation: {
editProfile: protectedResolver(resolveFn),
},
}
4. uploadPhoto.resolver.js
import prisma from '../../client'
import { uploadToS3 } from '../../shared/shared.utils'
import { protectedResolver } from '../../users/users.util'
export default {
Mutation: {
uploadPhoto: protectedResolver(
async (_, { file, caption }, { loggedInUser }) => {
let hashtagObj = []
if (caption) {
const hashtags = caption.match(/#[\w]+/g)
hashtagObj = hashtags.map((hashtag) => ({
where: { hashtag },
create: { hashtag },
}))
}
const fileUrl = await uploadToS3(file, loggedInUser.id, "uploads")
///shared/sahred.utils.js의 uploadToS3에 3개의 args를 보내서
///upload할 photo의 file을 S3의 bucket에 저장한 후 url을 return받음(fileUrl에)
return prisma.photo.create({
data: {
file: fileUrl,
caption,
user: {
connect: {
id: loggedInUser.id,
},
},
...(hashtagObj.length > 0 && {
hashtags: {
connectOrCreate: hashtagObj,
},
}),
},
})
}
),
},
}
5. Upload Type이 문제를 일으킬 수 있음.
밑의type들을 참고해서 upload type이 문제를 일으킬 경우 참고바람.
- shared/shared. resolvers.js
import { GraphQLUpload } from 'graphql-upload'
export default {
Upload: GraphQLUpload,
}
- editProfile.typeDefs.js
import { gql } from 'apollo-server'
import { GraphQLUpload } from 'graphql-upload'
export default gql`
scalar Upload
type EditProfileResult {
ok: Boolean!
error: String
}
type Mutation {
editProfile(
username: String
email: String
password: String
bio: String
avatar: Upload
): EditProfileResult!
}
`
- uploadPhoto.typeDefs.js
import { gql } from 'apollo-server'
import { GraphQLUpload } from 'graphql-upload'
export default gql`
scalar Upload
type Mutation {
uploadPhoto(file: Upload!, caption: String): Photo
}
`