Bleeding edge

환경에 따라 다른 서버로 Request 보내기 본문

Javascript

환경에 따라 다른 서버로 Request 보내기

codevil 2023. 8. 9. 09:34

분리가 필요했던 이유

package.json에 script와 process.env.NODE_ENV를 이용하여 production이나 development를 구분하는 방법도 있지만, vercel에서 배포를 하는 환경에서는 환경변수를 변경하여 사용하는 것이 편리하다고 생각하였고, 이번 프로젝트는 특히 서버에서 실행하는 알고리즘이 변경되는 일이 종종 있어서, production과 development는 그대로 유지하면서 local에서만 다른 알고리즘을 테스트 해보는 상황이 있었기 때문에 더욱 필요했다. 

Vercel

1. 수정하고 싶은 Project에 들어가서 Setting에 들어간다.

2. Environment Variables로 이동한다

3. process.env에서 사용할 Key와 Value를 입력한다.

(ex: key = NEXT_PUBLIC_API_MODE, value = production, environment = Development)

 

In Project

vecel로 배포를 하면 process.env.NEXT_PUBLIC_API_MODE를 입력하면 value로 입력했던 값을 사용할 수 있다.  baseURL을 사용하기 위하여 axios create를 사용한다. baseURL에 대한 option은 재활용이 될 가능성이 높기 때문에 class를 이용하여 instance를 생성하였다. baseURL은 vercel에서 설정한 환경변수를 이용하여 수정할 수 있도록 만들어야한다.

class ApiService {
  private readonly axiosInstance = axios.create({
    baseURL: '/', //이 부분에 vercel의 환경변수를 넣는다
    timeout: 60000
  });
}

환경 변수를 쉽게 수정할 수 있도록 두개의 class를 만들었다.

 

//BaseURL.ts
import envValidator from "./EnvValidator";

class ApiUrlStorage {
  public get baseUrl() {
    if (envValidator.isProduction) return this.productionBaseUrl;
    if (envValidator.isDevelopment) return this.developmentBaseUrl;
    return this.localBaseUrl;
  }

  private get localBaseUrl() {
    return "/local";
  }

  public get developmentBaseUrl() {
    return "/development";
  }

  private get productionBaseUrl() {
    return "/production";
  }
}

const apiUrlStorage = new ApiUrlStorage();

export default apiUrlStorage;
//EnvValidator

const ENV ={
  API_MODE: process.env.NEXT_PUBLIC_API_MODE as string,
}

class EnvValidator {
  get NODE_ENV() {
    return ENV.API_MODE;
  }
  get isProduction() {
    return this.NODE_ENV === "production";
  }
  get isDevelopment() {
    return this.NODE_ENV === "development";
  }
}

const envValidator = new EnvValidator();

export default envValidator;

이렇게 만들어 두면 .env파일을 넣지 않은 환경에서는 local 그리고 vercel에서 preview와 development에서는 development 그리고 production에서는 production으로 baseURL을 설정할 준비가 끝났다. 이제 위에 만들어둔 APIservice에 이 값을 넣어주자.

 

//api.service.ts
import { apiUrlStorage } from "./api.strorage";

class ApiService {
  private readonly axiosInstance = axios.create({
    baseURL: apiUrlStorage.baseUrl,
    timeout: 60000
  });
}

export const apiService = new ApiService();

이제 서버에 요청할 엔드 포인트를 넣어줄 클래스만 만들어주면 된다. (이 모든 케이스들을 모두 클래스로 만들 필요는 없다만 네임스페이스로 쉽게 분리하기 위해 클래스를 사용하였다.)

 

class ApiPathStorage {
  public get endPointExample() {
    return "/endpoint";
  }
}

export const apiPathStorage = new ApiPathStorage();

 

사용할 endpoint는 다음과 같이 사용하면 apiService 인스턴스를 이용하여 쉽게 request를 보낼 수 있다.

//api.service.ts
import { apiUrlStorage } from "./api.strorage";
import { apiPathStorage } from "./api.path";
class ApiService {
  private readonly axiosInstance = axios.create({
    baseURL: apiUrlStorage.baseUrl,
    timeout: 60000
  });
  public async getEndpoint(){
  	const { data } = await this.axiosInstance.get(apiPathStorage.endpointExample);
  }
}

export const apiService = new ApiService();

 

next.config.js

//next.config.js
const nextConfig = {
  //...나머지 next config
  async rewrites() {
    return [
      { 
        source: "/local/:path*",
        destination: "http://local.server/:path*" //로컬에서 사용할 서버 주소를 넣는다.
      },
      {
        source: "/development/:path*",
        destination: "http://development.server/:path*"//dev에서 사용할 서버 주소를 넣는다.
      },
      {
        source: "/production/:path*",
        destination: "https://production.server/:path*"//production에서  사용할 서버 주소를 넣는다.
      }
    ];
  },
};

module.exports = nextConfig;

 

확인

이제 위의 설정을 모두 마쳤다면, 브라우저의 network tab에서 request를 보낼 때 로컬의 경우에는 현재주소origin/local/endpoint, production에서는 현재주소origin/production/endpoint 에서 요청을 보낼 수 있게 되며, 도착지는 next.config.js에서 설정한 destination로 설정되어있다는 것을 확인할 수 있다.

 

마무리

서비스 배포하는 날에 axios에 대한 baseURL을 제대로 설정하지 않아서 엄청 고생한 기억이 있었고, 서비스를 배포하고 난 날 이후에 알고리즘을 테스트 하기 위한 서비스 분리가 많이 필요해서 이전에 사용되었던 레포를 이용하여 공부를 하였다. 어렵다기 보다는 한번 해보니 이런식으로도 환경변수를 사용할 수 있고, axios의 create와 option에 대해 공부할 수 있어서 좋았다.