Axios 헤딩 일지

강민수·2023년 1월 14일
0

vue3와 fastapi를 axios를 사용해 잇는 작업이다.

front에서 server쪽으로 보내는 쿼리는 정해져있고, 자주 사용하기 때문에 component마다 정의하는 것이 굉장히 비효율적이다. 또한 component마다 다른 속성을 지니고 있기 때문에 props를 통한 상속도 전체적으로 봤을 때 올바르지 않은 일이다.

그렇기 때문에 mixin을 사용한다.

서로다른 component이지만 공통된 기능을 지니고 있을 때 이런 공통된 함수를 mixin을 통해서 관리하자는 개념이다.

Mixin Usage

  1. mixin.js 파일을 생성한다.
export default{
    methods:{       
    }
}

해당 코드 안에 사용할 함수를 넣는다

  1. main.js에 mixin을 import 한다->import mixins from './mixins'
  2. main.js에서 mixin 등록한다 -> app.mixin(mixins)
  3. 각 component에서 this.{등록한 함수명}으로 간편하게 사용할 수 있다.

이제 mixin에 axios를 등록해야 한다.
진행할 작업은 fastapi로 지정된 data를 post방식으로 보내는 것이다.
그렇다면 필요한 것은
1. data 2. destination 3. method(post)만 존재하면 데이터를 보낼 수 있을것 같다!

이는 단순하게 axios함수에 method,url,data를 넘겨주기만 하면 되는 일이다. 그렇다면 다음과 같이 작성해서 함수를 넣고 실행해보자.

export default{
    methods:{
        async $api(url,method,data){
            return (await axios({
                method: method,
                url,
                data: data
            }).catch(e)).data;
        }
    }
}

이렇게 실행하면 422error를 만날 수 있다! 왜 이런 에러가 발생했을까?

422 error CORS

Fastapi에서 CORS정책을 사용중인데 이 정책을 만족시키지 못하여 422 error가 발생한 것이다.
그렇다면 이제 CORS정책에 맞게 정책설정을 해주어야 한다
fastapi에서

app = FastAPI()

origins = [
    "http://localhost:8080/",
]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

이런 방식으로 frontend의 origin을 등록해 주어야 한다.

Data format

mixin.js

import axios from 'axios';
export default{
    methods:{
        async $api(url,method,data){
            return (await axios({
                method: method,
                url,
                headers: { 'Content-Type': 'application/json' },
                data: JSON.stringify(data)
            }).catch(e=>{
                if(e.response.status === 422){
                    console.error(e.response.data);
                  }else{
                    console.error(e);
                  }
            })).data;
        }
    }
}

fastapi

class GameIn(BaseModel):
    category: str
    mode: str

@app.post("/gamestart")
async def img_return(info: GameIn):

axios 함수에서 json.stringfy 함수로 json화 시켜야 한다. 여기서 json방식으로 request를 보내기 위해서 request의 header 부분에서 Content-Type부분을 json을 전송할 수 있도록 바꾸어주어야 한다. 이렇게 작성된 함수는 request body를 통해 데이터가 전송된다.

fastapi에서 json 형식으로 데이터를 받지 않는다면, axios에서 params 파라미터에 key-value 쌍으로 값을 넣어주면 된다.

이제 데이터 형식까지 맞추었으니 전송이 될까?


(잘된다)

여담으로 vue3부터는 composition api가 mixin의 기능을 어느정도 대채하여? composition api를 사용하면 mixin을 굳이 사용하지 않아도 되는 것 같다

File 전송

file 전송은 또 다르다. 하지만 그렇게 다르지도 않다.

        async $api2(url,method,data){
            return (await axios({
                method: method,
                url,
                headers: {
                    'Content-Type': 'multipart/form-data'
                  },
                data
            }).catch(e=>{
                console.log(e);
            })
            ).data;

위와 같이 Content-Type을 multipart/form-data로 변경해주면 된다.
오히려 front단에서 더 애를 먹었는데,

async transformImg() {
	const formData = new FormData();
	formData.append('file', this.image);

	let response = await this.$api2('http://127.0.0.1:8000/api/v1/infer', 'POST', formData)
	this.returnImg = response['pred']
        },

중요한 것은 formData를 사용해야 한다는 것이다.
append를 통해 name-value matching으로 해당 key를 이용하여 backend에서 해당 값에 접근할 수 있다. 중간에 애먹었던 점은 이 formData를 이용해 데이터 전달이 잘 되는지 확인하기 위해 console.log를 찍어봤는데, 계속 아무것도 안찍혔다는 점이다! formData는 일반 문자열이나 객체가 아니라, 데이터 전송을 위해 특수하게 만들어진 객체라 그냥은 출력이 불가능 하다. key value를 순회하면서 출력하면 되는 것 같다.

<v-file-input clearable label="File input" variant="solo" v-on:change='setImg'></v-file-input>

추가적으로 vuetify에서 양방향 바인딩이 file에서도 제공되는 줄 알았는데, 아니였다. 기본적으로 vue 자체에서 file에 대하여 양방향 바인딩이 존재하지 않는다(파일 데이터가 바뀐다고 front 단에서 없는 파일이 나오는게 말이 안되긴 하다)

이렇게 전송된 데이터는 fastapi측에서 UploadFile로 간단하게 받아올 수 있고, 해당 데이터에 대한, 메타데이터 등의 parsing은 UploadFile에서 지원하는 method를 사용하면 된다.

파일과 다른 메타 정보를 함께 보내려면 어떻게 해야할까?

case1:

(meta,file: UploadFile = File(...)) // fastapi
meta는 parameter로 file은 body에서 form data로 들어가야 한다.

let response = await axios.post('url',formData,headers: {
          'Content-Type': 'multipart/form-data'},
          params:{meta:1} 
          } //vue
        
        
case2:

(file: UploadFile = File(...),meta=Body()) // fastapi
둘다 body에 들어가야함으로 meta 자체도 formdata로 들어가야 한다

formData.append(file,'file')
formData.append(meta,'meta')

let response = await axios.post('url',formData,headers: {
          'Content-Type': 'multipart/form-data'}
          }

formdata는 request body부분을 이용해 데이터를 전송하고 key-value pair를 이용하여 데이터를 전송하기 때문에 이런 전송이 가능한 것이다.

0개의 댓글