본문 바로가기

Development Note

Jersey 와 DynamoDB 를 이용한 간단 예제 만들기

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.



앞서서 Jersey 라는 Rest API 를 개발하기 위한 Framework 을 살펴보고 나서 상당히 흥미로왔는데요. 이를 배워보던 도중에 더 흥미로운 것을 또 발견해서.. 혹은 홀렸는지도 모르겠지만요. 여튼 근래 AWS 세미나를 한번 다녀오고 나서 Amazon 에서 제공하는 DynamoDB 를 사용해 봐야겠다고 느꼈습니다. 유기적으로 확장과 축소를 해줘야 하는 요새 웹 서비스에서 필요한 것이 아닐까 싶어서 한번 사용해 보았습니다.


생각보다 간단한 REST API 개발, 더 간단해보이는 DynamoDB 까지.. 이제는 복잡하고 과한 환경 설정과 기능보다는 필요한 것에 집중하는 형태의 라이브러리들이 많이 사랑을 받나봅니다. 개발자로서는 반가운 일이 아닐 수 없습니다.


DynamoDB 를 Java 를 통해서 사용하는 방법은 매우 간단했습니다. AWS SDK for JAVA 로 검색을 하면 AWS 에서 제공하는 관련 라이브러리 문서들을 쉽게 찾아 볼 수 있습니다. 제법 상세하고 체계적으로 잘 정리가 되어있으니 검색하여 보심이 좋겠습니다.


기본적으로 SDK 를 사용하는 절차는 쉽습니다. AWS 인증 정보를 통해서 각각의 모듈 Client 를 생성하여 사용하면 그걸로 끝입니다.


인증하는 소스를 잠깐 살펴보면 이렇습니다.


    private BasicAWSCredentials credentials;
    private AmazonDynamoDBClient client;

    public Service() {
        credentials = new BasicAWSCredentials("??", "??");
        client = new AmazonDynamoDBClient(credentials);
        client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1));
    }


?? 표시된 부분은 계정 정보 중 Security Credentials 항목 중 Access Keys 에서 생성할 수 있으니 적절하게 생성하여 쓰시면 됩니다. 이렇게 해서 만들어 진 BasicAWSCredentials 변수를 Client 중 하나인 AmazonDynamoDBClient 에 넣어주기만 하면 끝! 사용하기 위핸 기본적인 세팅이 매우 쉽습니다. 이렇게 해서 정말 AWS 관련 클라이언트를 사용할 수 있나 했는데.. 정말 되네요. 간단해서 좋네요 ^^


저는 간단하게 주소록을 만드는 API 를 만들어 보려 했습니다.


1. 간단한 개인 정보를 입력한다. (이름, 이메일, 전화번호 등)

2. 입력 된 개인정보를 조회하고 수정, 삭제하도록 한다.


한가지 데이터 모델을 정의하고 이와 관련된 CRUD 를 만들어 보는 것이 1차적인 목표입니다. 그 다음 단계도 있지만 그건 좀 해보고 이야기 해야죠 -_-; 처음 해야 할일은 모델링을 해야하는데 종래의 RDBMS 에서 테이블 만드는 것으로 접근을 해보니.. DynamoDB 에서 어떻게 입력을 해줘야 할지 난감 하더군요. DynamoDB Getting Start 라는 항목의 테이블을 생성하는 과정이 너무 심플해서 컬럼을 정의하고 하는 행위가 아예 없더라구요.


한참 이걸로 고민을 많이 했는데.. 결국 연락처에서 사용할 ID 를 하나 만드는 걸로 끝낼 수 있었습니다. 스키마가 필요없는 데이터 테이블에 스키마를 정의해 주려고 하니 진행이 안될 수 밖에요... RDB 에서 흔히 말하는 PK 혹은 CK(Combine Key) 를 정의해 주는 것 만으로 금방 완료가 되더라구요. 저 안에 어떠한 형태의 Attribute(RDB 에서는 Column) 가 존재할지는 넣는 사람 맘이 되어버리더군요. 신기합니다. 스키마가 정해져 있지 않은데도 생성이 되고 들어간다니..


그리고 나서 데이터를 집어 넣는 로직을 만들어 봅니다.


    @Path("/put")
    @PUT
    @Produces("application/json")
    public SGResponse put(@BeanParam User user) {
        SGResponse response = null;
        try {
            Map<String, AttributeValue> userObj = new HashMap<>();
            userObj.put("Id", new AttributeValue().withS(user.getId()));
            userObj.put("Name", new AttributeValue().withS(user.getName()));
            userObj.put("Email", new AttributeValue().withS(user.getEmail()));
            userObj.put("Mobile", new AttributeValue().withS(user.getMobile()));
            userObj.put("LoginDate", new AttributeValue().withS(dateFormatter.format(new Date())));

            PutItemRequest forumRequest = new PutItemRequest().withTableName(tableName).withItem(userObj);
            client.putItem(forumRequest);
            response = SGResponseFactory.createOK();
        } catch (ConditionalCheckFailedException cse) {
            System.err.println("Conditional check failed in " + tableName);
            return SGResponseFactory.createUnKnownError();
        } catch (AmazonServiceException ase) {
            System.err.println("Error updating item in " + tableName);
            return SGResponseFactory.createNoRecordError();
        }
        return response;
    }


이렇게 데이터를 입력 받아서 넣어주게 됩니다. javax.ws.rs-api 패키지에 있는 어노테이션을 통해서 API 형태를 구성해주고.. 사용할 파라미터도 xxParam 이라는 형태로 정의를 해주게 됩니다. 여러가지 xxParam 들이 존재하는데 저는 이중에 BeanParam 이라는 형태의 Object 형태의 파라미터를 사용했습니다. 대략적으로 Jersey 에 포함된 라이브러리의 사용은 여기가 끝입니다. Jersey 를 통해서 작업한 내용을 살펴보면..

  1. HTTP METHOD 의 정의 (GET, POST, PUT, DELETE 등)
  2. URL 경로 설정 (Path 어노테이션)
  3. API 호출 후에 Content-Type 정의 (Produces 어노테이션)
  4. 사용할 파라미터 정보 정의 (BeanParam 어노테이션)
정도로 정리를 할 수 있는데요. 이외에도 많은 설정 정보들이 있기 때문에 필요에 따라서 사용하면 참 편할 것 같습니다. Jersey 라는 친구가 많이 어렵지 않아서 좋네요. 이중에서 BeanParam 은 사용한 Object 에 추가해 주어야할 내용이 있습니다. 다음은 제가 구성한 User 라는 클래스의 모습입니다.

public class User {
    @FormParam("id")
    private String id;
    @FormParam("name")
    private String name;
    @FormParam("email")
    private String email;
    @FormParam("mobile")
    private String mobile;

    private Date loginDate;

    public User() {
        loginDate = new Date();
    }
FormParam 이라는 어노테이션이 눈에 띌텐데 BeanParam 하고 연관이 있습니다. BeanParam 으로 정의된 Object 를 생성하기 위해서 클라이언트의 Form 을 통하여 유입되는 파라미터를 매핑해주는 역할을 하는데, Form 을 통해서 들어온 id, name, email, mobile 이라고 정의된 변수에 각각의 이름에 맞게 매핑되어 들어갑니다. 참 쉽네요. 이 또한 어렵게 느껴질 수 있으나.. 결과물을 보면 매우 간단합니다. 이걸로 Jersey 의 영역은 끝!

다음 해주는 일들은 전부다 AWS SDK 를 사용한 소스입니다. 아, SGResponse 라는 클래스는 임의로 만들어서 사용하는 것이니 개의치 않고 스스로의 Return Type 을 정의하셔도 되고 javax.ws 패키지에서 제공하는 Response 를 사용하셔도 됩니다. 또한 꼭 Response 를 사용하는 것이 규칙은 아닙니다.

DynamoDB 를 사용하는 방법은 조금 더 간단합니다. 공식? 이랄건 없지만 형식이 굉장히 유사한데요. 알아볼 것들이 많으니 여기서는 일부의 기능만 쓰였습니다. 위에 입력 하는 소스를 살펴보면, String, AttributeValue 를 Key, Value 로 하여서 만든 Map Object 하나가 있고.. XXItemRequest 라는 녀석이 있고.. 그 이후에는 Client Object 를 사용하는 것으로 끝이 납니다. 또 한번 DynamoDB 를 정리해보면..

1. Map<String, AttributeValue> 오브젝트를 만들어서 정의된 Hash Key 를 포함한 Attribute 를 입력한다.

2. PutItemRequest 를 통해서 데이터를 넣은 테이블을 지정하고, 1번에서 작성한 Map 을 withItem 메소드를 통해서 넣어준다.

3. AmazonDynamoDBClient 의 Object 를 통해서 2번에서 생성한 PutItemRequest Object 를 인수로 하여 putItem() 메소드를 실행시켜주면 끝.


이 또한 매우 간결하고, 생성 뿐만아니라 삭제, 수정, 조회가 유사한 방식으로 동작하니 한가지를 알아놓으면 편할 것 같습니다. 특히나 AmazonDynamoDBClient 클래스에는 기능도 별로 없어서? 더 쉽게 익힐 수 있으니 좋네요. 다만 어려운 점이라면 DynamoDB 의 컨셉을 잘 이해해야 Client 를 사용하는데 무리가 없을 것이라는 점입니다. 석연치 않은 것들을 많이 남기고 가면 이해하는데 도움이 되질 않으니 그 역할과 목적을 명확하게 하고 감이 좋겠습니다.

이렇게 하여 크롬 Extension 을 사용하여 각각의 HTTP 메소드를 통해서 REST API 를 호출해 보았습니다. 


아래 다소 짤렸지만 Id값을 500 을 가지고 있는 User 데이터의 내용을 JSON 형태로 리턴을 하는 것을 볼 수 있습니다. 천천히 문서를 읽고 해보는데 큰 시간이 걸리지 않았으므로 쉽게 시도해 볼 수 있을 것 같습니다. 이렇게 데이터 소스를 선택하여 CRUD 를 구현해 보고 나면 이제 화면을 통해서 더 구현을 해봐야겠죠?화면은 Angular.js 를 통해서 시도를 해볼 생각입니다.


 Jersey 를 사용하면서 DynamoDB 를 사용하면서 느낀점 중에 하나는.. 개발자가 배워야 할 기술들이 많다보니 이렇게 간단하면서도 파워풀한 기능을 가진 라이브러리들을 익히는 것이 굉장히 효율적이겠다. 라는 점과.. 한번 더 AWS 의 강력함을 배워 나가는 기분입니다. 다소 어려울 것 같던 Jersey 는 상당히 쉽고 간결하고.. AWS 또한 그렇습니다.강력하다는 것과 심플하다는 느낌이 동시에 오기는 다소 어려운 것 같은데.. 지금 제 소감은 그렇습니다. ^^