본문 바로가기
백엔드/API

[API] S3로 파일 업로드하는 API

by eyoo 2022. 6. 24.

클라이언트를 통해 사진 같은 파일을 업로드할수있는 API를 만들어보자

 

먼저 Config 설정을 해야한다.

 

class Config:
    JWT_SECRET_KEY = 'yh20220621##hello'  # 절대 노출시키면 안되는 키
    JWT_ACCESS_TOKEN_EXPIRES = False # True로 설정하면 3분의 유효기간이 생긴다.
    PROPAGATE_EXCEPTIONS = True # JWT가 예외처리를 해주는 옵션

    # AWS eyoo1
    ACCESS_KEY = '여기에 엑세스 키를 입력'
    SECRET_ACCESS = '여기에 시크릿 엑세스를 입력'

    # 버킷 이름과 기본 URL주소 세팅
    S3_BUCKET = 'eyoo1-image-test'  # 버킷 이름
    S3_LOCATION = 'https://eyoo1-image-test.s3.amazonaws.com/' # 이 뒤에 버킷에 있는 객체 파일명을 붙이면 해당 파일의 URL이 된다.

# IAM에서 사용자를 추가했을때 받은 엑세스 키와 시크릿 엑세스를 변수로 저장한다.

# S3에서 만든 버킷 이름과 객체 주소를 변수로 저장한다. ( 객체 주소 형식: 프로토콜, 버킷이름, 's3.amazonaws.com' )

 

 

API를 만들기전에 S3로 사진 업로드에 필요한 라이브러리인 boto3 라이브러리를 설치한다.

 

pip install boto3

 

관련 링크: 

https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html

 

Quickstart — Boto3 Docs 1.24.16 documentation

Quickstart This guide details the steps needed to install or update the AWS SDK for Python. The SDK is composed of two key Python packages: Botocore (the library providing the low-level functionality shared between the Python SDK and the AWS CLI) and Boto3

boto3.amazonaws.com

 

 

이제 클래스를 새로 만들어서 업로드하는 API를 작성한다.

 

from flask_restful import Resource
from flask import request
from mysql.connector.errors import Error
from datetime import datetime
import boto3

from config import Config

# 사진올리는 클래스
class FileUploadResource(Resource) :

    def post(self):
        # 클라이언트에서 데이터를 받아온다.
        # request.files에 파일을 받아온다.
        # 따라서 파일이 없는 상태로 API가 호춣되면 에러메세지를 클라이언트에 응답해주자

        # photo란 클라이언트에서 보내는 key값이다.
        if 'photo' not in request.files:
            return{'error':'파일을 업로드 해주자'} , 400

        # 클라이언트로부터 파일을 받아온다.
        file = request.files['photo']

        # 파일명을 우리가 변경해준다.
        # 파일명은 유니크하게 만들어야 한다.
        current_time = datetime.now()
        new_file_name = current_time.isoformat().replace(':','_') + '.jpg'

        # 유저가 올린파일 이름을 내가 만든 파일명으로 변경한다.
        file.filename = new_file_name

        # boto3를 사용하여 S3에 업로드 한다.

        # 인증
        s3 = boto3.client('s3',aws_access_key_id= Config.ACCESS_KEY, aws_secret_access_key= Config.SECRET_ACCESS)

        # 파일업로드

        try:
            s3.upload_fileobj(file, Config.S3_BUCKET, file.filename, ExtraArgs = {'ACL':'public-read','ContentType':file.content_type})  # 파일, 버킷이름, 저장할 파일명 (키), 속성
        except Exception as e:
            return {'error':str(e)}, 500 


        return {'result':'success',
                'imgUrl':Config.S3_LOCATION + file.filename}

# photo는 클라이언트에서 보내는 key값이다.

# request.files에 photo 키값을 입력하여 클라이언트에 보내는 사진을 받아온다.

# S3에 사진을 업로드 할때 AWS의 라이브러리인 boto3를 사용한다.

# boto3의 client함수에 사용할 AWS 기능과 aws_access_key_id, aws_secret_access_key를 입력한다.

# upload_fileobj의 파라미터에는 파일, 버킷이름, 저장할 파일명 (키), 속성을 입력한다.

 

 

이제 포스트맨에서 테스트 하자.

 

body에 form-data를 선택한 후 key를 입력하고 'File'을 선택한다.

 

 

 

select file을 눌러 사진을 선택하고 send를 누른다.

 

 

 

 

그럼 S3서버에 사진이 저장된것을 볼수있다.

 

 

 

이를 활용하여 글과 사진을 함께 DB에 포스팅하는 API를 만들수있다.

 

 

from flask_restful import Resource
from flask import request
from mysql.connector.errors import Error
from mysql_connection import get_connection
from datetime import datetime
import boto3
from config import Config

class PostingResource(Resource):

    def post(self):

        # 1. 클라이언트로부터 데이터 받는다. photo, content (text)
        if 'photo' not in request.files:
            return {'error':'파일을 업로드 하세요'}, 400
        
        file = request.files['photo']
        content = request.form['content']

        # 2. S3에 파일 업로드

        # 파일명은 유니크하게 만들어야 한다.
        current_time = datetime.now()
        new_file_name = current_time.isoformat().replace(':','_') + '.jpg'

        # 유저가 올린파일 이름을 내가 만든 파일명으로 변경한다.
        file.filename = new_file_name

        # S3에 업로드 한다.

        # 인증
        s3 = boto3.client('s3',aws_access_key_id= Config.ACCESS_KEY, aws_secret_access_key= Config.SECRET_ACCESS)

        # 파일업로드

        try:
            s3.upload_fileobj(file, Config.S3_BUCKET, file.filename, ExtraArgs = {'ACL':'public-read','ContentType':file.content_type})  # 파일, 버킷이름, 저장할 파일명 (키), 속성
        except Exception as e:
            return {'error':str(e)}, 500 


        # 3. DB에 저장

        try:
            connection = get_connection()

            query =  '''insert into posting
                        (content, imgUrl)
                        values
                        (%s, %s);'''

            record = (content, new_file_name)

            cursor = connection.cursor()

            cursor.execute(query, record)

            connection.commit()

            cursor.close()
            connection.close()

        except Error as e:
            print (e)
            cursor.close()
            connection.close()
            return {'error':str(e)} , 503


        return {'result':'sucess'}

# 글은 request.form을 사용해서 파라미터로 저장할수있다.

 

 

 

 

 

 

댓글