AWS API Gateway + Lambda를 이용한 우회용 API 만들기
경고!!
어디까지나 우회용이기에 서비스에 따라서 위험할 수 있다. 일회성 혹은 단발성으로 필요하거나 보안을 무시해도 되는 상황에서 이 API 생성을 고려해보자.
AWS API Gateway + Lambda를 이용한 우회용 API를 만들어 보았다. 어떻게 만들었냐를 설명하기 전, 왜 이런게 필요했는지 어떤 상황이 있었는지 간단히 설명해보면 아래와 같다.
- 서비스 런칭 전, 모든 데이터는 테스트용 데이터일 때
- 비개발자 직원이 회원의 휴대폰 번호를 수정하고 싶다. 자주.
- 별도의 어드민 페이지가 없었기 때문에 편하게 수정하는 방법을 고민했다
환경 및 계획
당시 개발하던 서비스는 아래와 같은 환경이 준비되어 있었다.
- SpringBoot 3 + Kotlin + JPA
- Gradle
- SQS 사용을 위한 세팅 (io.awspring.cloud, 아래 참고)
// build.gradle.kts
dependencyManagement {
imports {
mavenBom("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.0")
}
}
dependencies {
implementation("io.awspring.cloud:spring-cloud-aws-sqs")
implementation("io.awspring.cloud:spring-cloud-aws-autoconfigure")
}
사용자는 비개발자인다. 그러니 쉬운 방법으로 휴대폰번호 수정이 되어야 한다. 인터넷 브라우저를 통해 파라미터를 전달할 수 있는 API를 만들려고 한다.하고자하는 방식은 아래와 같다.
- API Gateway에 GET 메소드의 API를 만든다.
- 이 API는 Lambda로 파라미터를 전달한다.
- Lambda에서는 SQS에 필요한 값을 전달한다.
- 서비스에서는 SQS에서 받은 메세지로 휴대폰 번호를 수정한다.
이미 서비스는 만들어져있다고 가정하면 필요한 것은 API Gateway의 API, Lambda, SQS이다. 이제 하나씩 생성해보자.
API Gateway
직원이 편하게 접근할 수 있는 End point를 만들기 위해 API를 생성해야 한다. 아래 이미지처럼 API 생성 버튼을 누른다.
위 이미지와 아래 내용을 참고해서 API를 만들어보자.
- REST API 선택 (프라이빗 아님)
- 프로토콜 : REST
- 새 API 생성 : 새 API
- 설정 : 자유롭게 API 이름을 작성
여기까지하면 생성한 API의 화면이 나타나게 된다. 이제 리소스와 메소드 생성을 해보자.
- 작업 버튼 클릭 - 리소스 생성
- 개발서버용과 운영서버용, 2개의 API를 만들 예정이라 리소스를 생성한다.
- 리소스 이름 : 자유롭게 작성한다. 필자의 경우에는 개발서버용으로 'dev'라고 작명했다.
- 리소스 경로 : 자동으로 입력되기도 한다. 변경하고 싶다면 변경해도 된다.
- 메소드 생성 방법
- 방금만든 리소스 선택 (필자의 경우, /dev)
- 작업 클릭 - 메소드 생성 클릭 - GET 선택 (브라우저 URL 입력란을 활용하기 위함)
- 통합 유형 : Lambda 함수
이제 엔드포인트 생성은 완료했다. 아직 메소드가 완전히 정의되지 않아서 API 배포는 할 수 없다. Lambda에 적절한 로직을 만든 뒤 API 배포를 해보자.
Lambda
엔드포인트의 파라미터를 전달받아서 원하는 로직을 수행시키고 싶다. 그 로직을 Lambda에 담으려고 한다. 아래 설명과 이미지를 참고해서 Lambda를 만들어보자.
- AWS Lambda 서비스를 선택한다.
- 함수 생성 버튼을 클릭한다.
- 함수 이름 : 자유롭게 작성
- 하단의 함수 생성 버튼 클릭 - 몇 초 후에 Lambda가 생성
- 코드탭 - 필요한 로직을 입력. 개발 완료 후 Deploy 버튼을 클릭하는 것을 잊지말자.
코드 내부에는 SQS 메세지를 전송하는 로직이 있어야 한다. 해당 메세지를 내가 개발한 애플리케이션에서 받을 목적이다. 예시 코드를 아래에 남기겠다.
다음은 Lambda에 입력할 예시 코드이다. QueueUrl은 비워도 된다. 뒤에서 설명하면서 SQS 생성 설명하면서 QueueUrl에 해당하는 것도 설명하겠다. event 인자는 API의 파라미터를 전달한다.
import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs";
export const handler = async(event) => {
const sqs = new SQSClient({ region: "ap-northeast-2" });
const data = JSON.stringify({
event_type: "MY_TEST",
parameter1: event.queryStringParameters.parameter1,
parameter2: event.queryStringParameters.parameter2
});
console.log(data)
const params = {
MessageBody: data,
QueueUrl: "https://sqs.ap-northeast-2.amazonaws.com/123456789/my-queue",
MessageAttributes: {
AttributeName: {
StringValue: "Attribute Value",
DataType: "String",
}
}
};
try {
const response = await sqs.send(new SendMessageCommand(params));
// 현재 시간 구하기
const currentTime = new Date();
currentTime.setHours(currentTime.getHours() + 9);
const year = currentTime.getFullYear();
const month = String(currentTime.getMonth() + 1).padStart(2, '0');
const day = String(currentTime.getDate()).padStart(2, '0');
const hours = String(currentTime.getHours()).padStart(2, '0');
const minutes = String(currentTime.getMinutes()).padStart(2, '0');
const seconds = String(currentTime.getSeconds()).padStart(2, '0');
const formattedTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
console.log(formattedTime);
return {
statusCode: 200,
body: JSON.stringify({
created_at: formattedTime,
parameter1: event.queryStringParameters.parameter1,
parameter2: event.queryStringParameters.parameter2
})
}
}
catch (e) {
console.log(e)
}
};
이제 생성한 Lambda를 앞에서 만든 API와 연결해주자. 다시 API Gateway 화면으로 진입하자.
- API Gateway 화면 - GET 메소드 선택
- Lambda 함수 : 방금 생성한 Lambda를 검색해서 선택 - 저장 버튼 클릭
- Lambda 화면으로 진입하면 위 이미지의 트리거 추가 버튼이 있던 자리에 API Gateway가 보인다
API 요청 및 응답 (Request & Response)
만약 이 API에 특정값을 전달하고 싶을 수 있다. 필자의 경우에는 GET 메소드 API에 파라미터를 넣고 싶었다. 예를 들면 아래와 같은 형태이다. parameter1, parameter2를 이용하여 원하는 파라미터를 전달하고 있다.
https://sample.abcdef.com/xyz/dev?parameter1=aaa¶meter2=bbb
방법은 간단하다. 리소스의 GET을 클릭하고 메서드 요청 버튼을 클릭하면 아래와 같은 화면이 나온다. 여기서 쿼리 문자열 추가를 눌러서 원하는 "파라미터 이름"을 입력한다. 해당 파라미터를 필수로 입력하게 할 건지도 정할 수 있다. 이 파라미터 이름은 Lambda의 event 인자의 queryStringParameters와 일치시킨다. 위 Lambda 예시코드를 참고하자.
요청에 따른 응답값을 받고 싶을 수 있다. 이는 생각보다 간단하게 처리할 수 있다.
- 당연히 Lambda 화면 - 코드에 return값이 있어야 한다.
- 위에 안내한 Lambda의 예시 코드 내부에 return 부분을 참고하면 된다.
- API Gateway 화면 - GET 메소드 선택 - 통합 요청 클릭 (이때 유형: Lambda)
- Lambda 프록시 통합 사용 체크 - 팝업 화면 확인
- 다시 GET 메소드 선택 - 통합 요청 - 유형: LAMBDA_PROXY로 변경된 것을 확인할 수 있다
API 배포
API를 만들었지만 사용할 수 없는 상태다. API를 배포해야 비로소 사용할 수 있다. 배포 방법은 다음과 같다.
- API Gateway - 앞에서 만든 API 선택
- GET 선택 - 작업 버튼 클릭 - API 배포 클릭
- 배포 스테이지 : [새 스테이지] 선택
- 스테이지 이름 : 자유롭게 작성
- 스테이지 화면 - 상단 "URL 호출"에서 URL을 확인할 수 있다
- 참고 : 1개의 스테이지에 여러개의 리소스를 적용할 수 있다.
Gateway에 수정을 했다면 반드시 다시 배포를 해야 한다. 배포 전에는 반영했던 사항이 적용되지 않는다. 다시 배포하는 방법은 위에서 안내한 방법에서 배포 스테이지 선택 부분만 바뀐다. 생성한 스테이지 이름을 선택하면 된다. 이제 파라미터와 스테이지 URL을 조합해서 아래와 같은 형태를 완성할 수 있다. 이 URL을 인터넷 브라우저에 입력하면 API가 동작한다.
<1개의 스테이지에 여러개의 리소스를 적용한 예시>
test 스테이지의 dev 리소스
- https://abcd1234.execute-api.ap-northeast-2.amazonaws.com/test/dev?parameter1=aaa¶meter2=bbb
test 스테이지의 prod 리소스
- https://abcd1234.execute-api.ap-northeast-2.amazonaws.com/test/prod?parameter1=aaa¶meter2=bbb
SQS
아직 끝난게 아니다. SQS를 생성해야 한다. 이전에 간단하게 SQS 생성한 내용을 작성한 것이 있다. 생성 부분은 여기를 참고하자. 생성을 완료하면 상단의 세부 정보에서 URL을 확인할 수 있다. 이를 복사해서 위 Lambda 코드 내부의 QueueUrl에 입력하면 된다.
이렇게 해서...
- 인터넷 브라우저 URL 입력창 : Gateway 스테이지 URL을 파라미터와 함께 입력하면
- Gateway : API는 파라미터 전달과 함께 Lambda를 동작시킨다
- Lambda : 파라미터를 메세지에 담아 SQS에 올리면
- 내 애플리케이션 : SQS로부터 메세지를 수신받아 원하는 기능을 수행한다.
뭔가 찜찜한 개발에 뭔가 부족한 설명이지만 이후에 설명거리가 늘어나면 더 보충해보겠다. 그럼 여기까지. 안뇽.
.