내 두 이전 블로그 게시물에서 Ratpack과 경량 ODM 레이어를 소개한 적이 있습니다. Java SDK. 이 게시물에서는 이를 기반으로 Couchbase 리포지토리를 통해 사용자를 관리할 수 있는 REST API를 소개합니다.
API가 네 가지 기본 HTTP 동사를 지원하고 콘텐츠 유형을 지원하기를 원합니다. Ratpack에서는 이를 위해 모든 것이 고려되었습니다. 그리고 체인 객체는 핸들러를 작성하는 빌더와 같습니다. 그래서 저는 새로운 액션 클래스를 사용하여 체인을 'user' URL 접두사에 바인딩할 수 있습니다. 이렇게 하면 제 기본 메서드가 훨씬 단순해집니다:
1 2 3 4 5 6 |
public 정적 void 메인(문자열... args) 던지기 예외 { RxRatpack.초기화(); RatpackServer.시작(서버 -> 서버.레지스트리(Guice.레지스트리(b -> b.모듈(구성.클래스))) .핸들러(체인 -> 체인.접두사("user", 사용자 핸들러.클래스))); } |
사용자 핸들러 인스턴스를 찾을 수 있도록 하려면 구성 가이드 모듈에도 추가해야 합니다:
1 2 3 4 5 6 7 8 9 10 11 12 |
public 클래스 구성 확장 AbstractModule { 보호됨 void 구성() { 카우치베이스클러스터 cc = 카우치베이스클러스터.create(); 버킷 버킷 = cc.오픈버킷(); 바인드(비동기 버킷.클래스).toInstance(버킷.비동기()); 바인드(비동기 저장소.클래스).toInstance(버킷.저장소().비동기()); 바인드(사용자 핸들러.클래스); 바인드(사용자 렌더러.클래스); } } |
또한 다양한 콘텐츠 유형을 처리하는 데 사용되는 UserRenderer 클래스를 추가합니다.
커스텀 렌더러
Ratpack에서는 새로운 렌더러 지원 클래스입니다. 이들의 목표는 T 객체를 렌더링하는 방법을 지정하는 것입니다. 컨텍스트. 제 경우에는 컨텍스트 콘텐츠 유형에 따라 사용자 객체를 렌더링하고 싶습니다. 컨텍스트 객체는 콘텐츠별 메서드를 사용하여 요청에 설정된 콘텐츠 유형에 따라 렌더링을 구성할 수 있습니다. 일반적인 유형은 이미 미리 정의되어 있습니다. 제 경우에는 json과 텍스트만 지원하고 싶습니다:
1 2 3 4 5 6 7 8 9 10 11 12 |
public 클래스 사용자 렌더러 확장 렌더러 지원<사용자> { @오버라이드 public void 렌더링(컨텍스트 컨텍스트, 사용자 사용자) 던지기 예외 { 컨텍스트.콘텐츠별(byContentSpec -> byContentSpec .json(() -> 컨텍스트.렌더링(Jackson.json(사용자))) .일반 텍스트(() -> 컨텍스트.렌더링(사용자.toString())) ); } } |
텍스트 렌더링은 간단한 toString()을 사용합니다. JSON 버전은 Ratpack에서 기본적으로 제공되는 Jackson 객체를 사용합니다. 이를 통해 JSON/객체 변환을 위한 단축키에 액세스할 수 있습니다. User 객체를 인수로 제공하는 json 메서드를 호출하면 됩니다. 잭슨은 내부적으로 Java SDK에서도 사용됩니다. 하지만 트릭이 있습니다. Couchabse ODM에 사용한 @Field 어노테이션은 Ratpack에서 사용되는 기본 Jackson 매퍼가 인식하지 못합니다. 따라서 이를 보완하기 위해 Jackson @JsonProperty 어노테이션을 추가해야 합니다. 애초에 @Field 어노테이션을 사용하지 않았다면 아무것도 추가할 필요가 없었을 것입니다. 더 나은 방법을 찾도록 노력하겠지만 당분간은 잘 작동합니다.
1 2 3 4 5 6 7 8 |
@필드("fName") @제이슨 프로퍼티("fName") 비공개 문자열 이름; @필드("lName") @제이슨 프로퍼티("lName") 비공개 문자열 성; |
핸들러로 API 구성하기
이제 API 작업을 시작할 수 있는 좋은 위치에 있습니다. GET, PUT, DELETE가 작동하려면 사용자 아이디가 필요합니다. 그래서 제가 가장 먼저 하는 일은 /user/ URL 뒤에 무언가가 있는지 확인하는 것입니다. 핸들러는 모두 체인으로 연결되어 있으며 선언한 순서대로 실행됩니다. 일단 핸들러에 들어가면 체인이 멈춥니다. 따라서 /user/ 앞에 /user/:userId를 선언해야 합니다. 경로 바인딩은 정규식을 사용하며, 그 예는 체인 문서.
전화로 경로
메서드를 사용하면 경로 정규식과 핸들러를 인수로 전달할 수 있습니다. 핸들러에서 먼저 경로 토큰에서 Couchbase 리포지토리와 userId를 가져옵니다. 그런 다음 byMethod 메서드를 사용하여 지원해야 하는 각 HTTP 동사에 대한 함수를 정의할 수 있습니다. 여기서는 GET의 경우 사용자를 반환하고, PUT의 경우 사용자를 업데이트하거나 생성하고, REMOVE의 경우 사용자를 제거하겠습니다.
여기서 가장 흥미로운 동사는 요청에 콘텐츠가 필요하기 때문에 PUT입니다. 컨텍스트 parse
메서드는 Parse 객체를 인수로 전달하고 Promise를 반환합니다. 여기서는 요청에서 JSON을 파싱하여 User 객체에 매핑하고 싶습니다. 따라서 Promise를 반환합니다. 저는 RxJava 사용자이므로 해당 Promise를 Observable에 매핑한 다음 User 객체를 EntityDocument에 매핑하여 최종적으로 Couchbase 리포지토리에 저장합니다. 그런 다음 해당 관찰 가능 항목을 다시 ratpack 프로미스로 변환하고 간단한 확인 문자열을 다시 전송합니다. 실제 사례에서는 좀 더 스마트한 작업을 하고 싶을 수도 있습니다.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
체인.경로(":userId", ctx -> { 비동기 저장소 repo = ctx.get(비동기 저장소.클래스); 문자열 userId = ctx.getPath토큰().get("userId"); ctx.byMethod(메서드스펙 -> { 메서드스펙.get(() -> { 관찰 가능<엔티티도큐먼트<사용자>> 사용자 = repo.get(userId, 사용자.클래스); RxRatpack.약속(사용자).다음(u -> ctx.렌더링(u.get(0).콘텐츠())); }).put(() -> { 약속<사용자> 약속 = ctx.parse(Jackson.fromJson(사용자.클래스)); 관찰 가능<엔티티도큐먼트<사용자>> 관찰 가능 = RxRatpack.관찰(약속) .지도(사용자 -> 엔티티도큐먼트.create(사용자)).플랫맵(doc -> repo.업서트(doc)); RxRatpack.약속(관찰 가능).다음(doc -> ctx.렌더링("OK")); }).삭제(() -> { 관찰 가능<엔티티도큐먼트<사용자>> 사용자 = repo.제거(userId, 사용자.클래스); RxRatpack.약속(사용자).다음(u -> ctx.렌더링("OK")); }); }); }); |
사용자 아이디가 필요한 HTTP 동사가 구현되면 다른 모든 동사는 끝낼 수 있습니다. 그리고 다음 메서드를 사용하면 쉽게 할 수 있습니다. 모두
. 여기서 레지스트리에서 리포지토리와 버킷을 가져옵니다. 그런 다음 GET 메서드의 경우 사용자 ID가 없으므로 전체 사용자 목록을 반환합니다. 이를 위해 기본 N1QL 쿼리를 실행합니다. 마지막으로 POST는 PUT 메서드와 동일합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
체인.모두(ctx -> { 비동기 버킷 버킷 = ctx.get(비동기 버킷.클래스); 비동기 저장소 repo = ctx.get(비동기 저장소.클래스); ctx.byMethod(메서드스펙 -> { 메서드스펙.get(() -> { N1qlQuery 쿼리 = N1qlQuery.simple("SELECT Meta().id as username,age,fName,lName FROM default WHERE type = 'user'"); 관찰 가능<사용자> 관찰 가능 = 버킷.쿼리(쿼리) .플랫맵(qRes -> qRes.행()).지도(행 -> { JsonObject jo = 행.값(); 문자열 사용자 이름 = jo.getString("username"); 정수 나이 = jo.getInt("age"); 문자열 fName = jo.getString("fName"); 문자열 lName = jo.getString("lName"); 반환 new 사용자(사용자 이름, 나이, fName, lName); }); RxRatpack.약속(관찰 가능).다음(사용자 -> ctx.렌더링(Jackson.json(사용자))); }).post(() -> { 약속<사용자> 약속 = ctx.parse(Jackson.fromJson(사용자.클래스)); 관찰 가능<엔티티도큐먼트<사용자>> 관찰 가능 = RxRatpack.관찰(약속) .지도(사용자 -> 엔티티도큐먼트.create(사용자)).플랫맵(doc -> repo.업서트(doc)); RxRatpack.약속(관찰 가능).다음(doc -> ctx.렌더링("OK")); }); }); }); |
완전히 만족스러운 API는 아니지만 Ratpack, Couchbase 및 RxJava로 얼마나 쉽게 만들 수 있는지에 대한 좋은 아이디어를 얻을 수 있을 것입니다. 카우치베이스 모듈과 같이 Ratpack과 관련된 더 많은 내용을 보고 싶으시면 알려주세요.