다음과 같은 API 요청과 API 응답을 가지는 REST API를 Lambda 함수와 API Gateway를 이용하여 구축해본다.
API 요청
GET /devices/{deviceId}
응답 모델
{
"state": {
"desired": {
"attribute1": integer2,
"attribute2": "string2",
...
"attributeN": boolean2
},
"reported": {
"attribute1": integer1,
"attribute2": "string1",
...
"attributeN": boolean1
},
"delta": {
"attribute3": integerX,
"attribute5": "stringY"
}
},
"metadata": {
"desired": {
"attribute1": {
"timestamp": timestamp
},
"attribute2": {
"timestamp": timestamp
},
...
"attributeN": {
"timestamp": timestamp
}
},
"reported": {
"attribute1": {
"timestamp": timestamp
},
"attribute2": {
"timestamp": timestamp
},
...
"attributeN": {
"timestamp": timestamp
}
}
},
"timestamp": timestamp,
"clientToken": "token",
"version": version
}
–
생성된 * GetDeviceLambda*의 build.gradle 파일을 열고, 다음 의존성을 추가하고, 변경사항을 반영합니다.
dependencies {
...
implementation platform('com.amazonaws:aws-java-sdk-bom:1.12.529')
implementation 'com.amazonaws:aws-java-sdk-iot'
...
}
src/main/java/helloworld/App.java 파일을 다음 코드로 바꿉니다.
package helloworld;
import com.amazonaws.services.iotdata.AWSIotData;
import com.amazonaws.services.iotdata.AWSIotDataClientBuilder;
import com.amazonaws.services.iotdata.model.GetThingShadowRequest;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
/**
* Handler for requests to Lambda function.
*/
public class App implements RequestHandler<Event, String> {
public String handleRequest(final Event event, final Context context) {
AWSIotData iotData = AWSIotDataClientBuilder.standard().build();
GetThingShadowRequest getThingShadowRequest =
new GetThingShadowRequest()
.withThingName(event.device);
String output = new String(
iotData.getThingShadow(getThingShadowRequest).getPayload().array());
return output;
}
}
class Event {
public String device;
}
–
작성된 Lambda함수가 정상적으로 동작하는 지를 테스트해 보기 위해서 다음 절차를 수행합니다.
IntelliJ IDEA IDE의 화면 상단 타이틀 바에서 “[Local] HelloWorldFunction” 옆의 연두색 실행 버튼 (삼각형)을 클릭
[Edit Configuration] 다이얼로그 화면에서 Text – Event Templates – 부분의 드롭다운 메뉴 중에서 API Gateway AWS Proxy를 선택하고, 다음 입력 문자열을 입력한다.
조회할 사물의 이름이 MyMKRWiFi1010인 경우를 가정
{
"device" : "MyMKRWiFi1010"
}
Console 창에 다음과 같은 형식의 메시지가 마지막에 출력되는 지 확인합니다. (본인의 aws 계정에 생성된 사물의 상태가 Json 형식으로 반환됨)
...
SSTART RequestId: e49a9f7e-bf5d-415a-b72d-9e5754830e79 Version: $LATEST
Picked up JAVA_TOOL_OPTIONS: -XX:+TieredCompilation -XX:TieredStopAtLevel=1
END RequestId: e49a9f7e-bf5d-415a-b72d-9e5754830e79
REPORT RequestId: e49a9f7e-bf5d-415a-b72d-9e5754830e79 Init Duration: 0.82 ms Duration: 12795.96 ms Billed Duration: 12796 ms Memory Size: 512 MB Max Memory Used: 512 MB
"{\"state\":{\"desired\":{\"welcome\":\"aws-iot\"},\"reported\":{\"temperature\":\"22.30\",\"LED\":\"OFF\",\"welcome\":\"aws-iot\"}},\"metadata\":{\"desired\":{\"welcome\":{\"timestamp\":1697592894}},\"reported\":{\"temperature\":{\"timestamp\":1697772333},\"LED\":{\"timestamp\":1697772333},\"welcome\":{\"timestamp\":1697592894}}},\"version\":1117,\"timestamp\":1699062480}"
–
GetDeviceLambda 프로젝트 탐색창에서 template.yaml을 찾아서 선택하고, 선택된 상태에서 오른쪽 마우스 클릭하여 SyncServerless Application (formerly Deploy) 메뉴를 선택
[Confirm development stack] 다이얼로그 화면에서 Confirm 선택
[SyncServerless Application (formerly Deploy)] 다이얼로그 화면에서, Create Stack에 적절한 이름(예, GetDeviceLambda)을 입력 하고, S3 Bucket 중에 하나를 선택(S3 Bucket이 없으면 Create 버튼을 눌러 생성 후 선택)하고, CloudFormation Capabilities: 에서 IAM 체크박스를 선택한 후, Sync 클릭
콘솔 창에 다음 결과가 맨 마지막 줄에 출력되는 지를 확인
...
Stack creation succeeded. Sync infra completed.
Process finished with exit code 0
–
AWS Lambda함수가 다른 AWS 서비스 (예, DynamoDB)를 사용하기 위해서는 필요한 권한이 Lambda함수에 연결된 실행 역할 정책(Execution Role Polcity)에 포함되어 있어야 합니다.
람다함수의 실행 역할 정책 업데이트
원격 테스트를 위해서 AWS Toolkit 창의 탐색기에서 Lambda를 확장하여 GetDeviceLambda-HelloWorldFunction-XXX선택하고, 오른쪽 마우스 클릭하여 Run ‘[Remote] HelloServer…‘메뉴를 선택
–
탬플릿 생성 드롭다운 메뉴에서 메서드 요청 패스스루를 선택하고, 템플릿 본문에 다음을 입력합니다.
{
"device": "$input.params('device')"
}
이는 Lambda 함수에 전달될 payload를 구성하는 템플릿으로서, “device” 속성 값을 /{device} 경로변수의 값으로 사용하겠다는 의미입니다.
테스트를 클릭하고, 다음과 같은 결과가 나오는 지 확인합니다.
/devices/{device} - GET 메서드 테스트 결과
...
응답 본문
"{\"state\":{\"desired\":{\"welcome\":\"aws-iot\",\"temperature\":\"25.1\",\"LED\":\"OFF\"},\"reported\":{\"temperature\":\"24.50\",\"LED\":\"OFF\",\"welcome\":\"aws-iot\"},\"delta\":{\"temperature\":\"25.1\"}},\"metadata\":{\"desired\":{\"welcome\":{\"timestamp\":1697592894},\"temperature\":{\"timestamp\":1699157194},\"LED\":{\"timestamp\":1699157194}},\"reported\":{\"temperature\":{\"timestamp\":1699158494},\"LED\":{\"timestamp\":1699158494},\"welcome\":{\"timestamp\":1697592894}}},\"version\":1145,\"timestamp\":1700158284}"
...
–
JavaScript는 Cross-Origin Resource Sharing (CORS) 요청을 기본적으로 제한합니다. 즉, JavaScript 코드가 동일 서버 내의 리소스를 접근하는 것은 허용하지만, 다른 서버의 리소스를 사용하고자 하는 경우에는 CORS 헤더 정보가 포함되어 있어야 합니다.
REST API 리소스에 대해 CORS 지원 활성화
지금까지 API를 생성했지만 아직 실제로 사용할 수는 없습니다. 배포해야 하기 때문입니다.
–
get_device_state.html 시작 html 페이지
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AWS Open API Sample</title>
<!-- JQuery 라이브러리 설정 -->
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<!-- 디바이스 조회 자바스크립트 로딩-->
<script src="device_state.js"></script>
</head>
<body>
<h3>My AWS API Sample</h3>
<input type="button" value="조회 시작" onclick="Start();" />
<input type="button" value="조회 중지" onclick="Stop();" />
<h4>나의 디바이스 최신 상태</h4>
<div id="result">No Data</div>
</body>
</html>
device_state.js: JQuery 기반 Javascript 코드
// 중지를 위해 ID 보관
var intervalId = null;
// API 시작
function Start() {
invokeAPI();
intervalId = setInterval(invokeAPI, 1000);
document.getElementById("result").innerHTML="조회 중...";
}
// API 중지
function Stop() {
if(intervalId != null) {
clearInterval(intervalId);
document.getElementById("result").innerHTML="No Data";
}
}
var invokeAPI = function() {
// 디바이스 조회 URI
// prod 스테이지 편집기의 맨 위에 있는 "호출 URL/devices"로 대체해야 함
var API_URI = 'https://XXXXXXXXXX.execute-api.ap-northeast-2.amazonaws.com/prod/devices/MyMKRWiFi1010';
$.ajax(API_URI, {
method: 'GET',
contentType: "application/json",
success: function (data, status, xhr) {
var result = JSON.parse(data);
printData(result); // 성공시, 데이터 출력을 위한 함수 호출
console.log("data="+data);
},
error: function(xhr,status,e){
alert("error");
}
});
};
// 데이터 출력을 위한 함수
var printData = function(result){
document.getElementById("result").innerHTML = "temp: "+ result.state.reported.temperature +
", LED: " + result.state.reported.LED;
}
초기화면
조회 버튼을 클릭한 후