본문 바로가기
Rust/프로젝트

Rust로 백엔드 개발기(feat. 메이플스토리) - 08 사용자별 요청 처리

by lms0806 2025. 3. 31.
728x90
반응형

이번 시간에는 user_ocid 값을 어떻게 사용자별로 사용하여 api를 호출할 수 있는지에 대해 다뤄보고자 합니다.

 

현재 maplestory open api를 활용하는 프로젝트에서 rust의 axum을 활용하여 백엔드를 개발중인 상태입니다.

 

maple open api에서는 getOcid를 통하여 사용자 ocid값을 가져오고, 이를 다른 사용자 관련 다른 api들에서 해당 ocid 값을 통하여 통신을 진행합니다.

 

그러다보면, getOcid로 가져온 값이 사용자별로 다르게 작동해야만 합니다.

 

이 부분은 frontend와 통신을 진행하면서 어떤 방법으로 사용자를 특정지어 사용할 것인지에 대하여 이야기가 필요합니다.

 

해당 포스팅을 통하여 frontend와 이야기를 통해 진행하고자 했던 방식들에 대하여 이야기해보고자 합니다.

방법 1 header를 통한 구분

rest api에서는 header에 key, value로 특정 값에 대한 정보를 전달할 수 있습니다.

 

그리고, frontend에서는 sessionstorage나 localstorage를 통하여 특정 사용자에 대한 uuid를 가져올 수 있습니다.

 

이 방식을 통하여 uuid에 따른 ocid값을 백엔드에서 들고 있고 이를 활용하여 사용자에 따른 ocid값으로 다른 api들을 활용한 결과를 전달할 수 있습니다.

pub struct API {
    pub key: String,
    pub ocid: DashMap<String, String>,
}

기존 API 구조체의 ocid값과는 다르게 DashMap<String, String>로 지정하여, key와 value 형식으로 할 수 있습니다.

 

ocid map의 value를 가져오기 위한 방법으로 해당 구조체에 대한 함수를 만들어 활용할 수 있습니다.

impl API {
    // 생성자
    pub fn new(key: String) -> Self {
        Self {
            key,
            ocid: DashMap::new(),
        }
    }

    // uuid에 해당하는 ocid 값을 가져옵니다.
    pub fn get_ocid_uuid(&self, uuid: &str) -> Option<String> {
        self.ocid.get(uuid).map(|entry| entry.value().clone())
    }

    // uuid에 해당하는 ocid 값을 설정합니다.
    pub fn set_ocid_uuid(&self, uuid: String, ocid: String) {
        self.ocid.insert(uuid, ocid);
    }
}

get_ocid 요청을 수행한 후에, set_ocid_uuid를 통하여 uuid값에 따른 ocid값을 map에 넣어줍니다.

 

이후, 다른 api 요청 수행시, 다음과 같이 header에서 uuid값을 가져와 get_ocid_uuid를 통하여 uuid에 따른 ocid값을 가지고 사용자별 요청을 수행할 수 있습니다.

let uuid = header
        .get("uuid")
        .and_then(|value| value.to_str().ok())
        .unwrap_or_default();

header에서 uuid값을 가져오기 위해서는 axum::http::HeaderMap을 필요로 합니다.

pub async fn get_ocid(
    Extension(api_key): Extension<Arc<API>>,
    header: HeaderMap,
    Json(character): Json<Character>,
) -> Result<Json<UserOcid>, (StatusCode, &'static str)> {}

여기서 주의해야할 점은 HeaderMap의 인자값 위치는 항상 JsonBody보다 상단에 있어야만 작동합니다.

use axum::{extract::State, http::{Method, HeaderMap}};

async fn handler(
    // `Method` and `HeaderMap` don't consume the request body so they can
    // put anywhere in the argument list (but before `body`)
    method: Method,
    headers: HeaderMap,
    // `State` is also an extractor so it needs to be before `body`
    State(state): State<AppState>,
    // `String` consumes the request body and thus must be the last extractor
    body: String,
) {
    // ...
}

방법 2 요청마다 ocid값을 받음

이 부분은 사용자별 ocid에 대한 처리를 frontend에서 처리하고 화면단에서 ocid값을 전달받아 이를 api를 활용하는데 사용되는 방식입니다.

 

다음과 같은 방식을 활용하는 경우, header 관련 작업을 수행하지 않는 다는 점에서 백엔드한테는 이점이 될 수 있습니다.

 

그러나, 모든 요청의 body에 ocid값을 전달받으므로, get 요청이 아닌 post요청으로만 이루어져 있다는 불편함이 있을 수 있습니다.

pub async fn get_user_default_info(
    Extension(api_key): Extension<Arc<API>>,
    Json(user_ocid): Json<UserOcid>,
) -> Result<Json<UserDefaultData>, (StatusCode, &'static str)> {}

다음과 같이 모든 요청에 Json(user_ocid): Json<UserOcid> 해당 값을 필요로 하여 jsonBody에 ocid 값을 전달받아 사용하면 됩니다.

 

다음 시간에는 main함수에 선언한 불필요한 내용들을 분리하는 방법에 대해 배워보고자 합니다.

728x90
반응형

댓글