계속 지켜보셨다면 아시겠지만 저는 Node.js 개발과 JavaScript 개발 스택의 열렬한 옹호자입니다. 이전에는 Couchbase, Express, AngularJS 및 Node.js(CEAN) 스택 그리고 Hapi.js로 백엔드 API 현대화의 인기 있는 대안입니다. 저는 Angular의 열렬한 팬이지만 최근에는 점점 더 인기를 얻고 있는 Vue.js 프레임워크를 살펴보고 있습니다.
Node.js, Hapi, Vue.js로 구성된 JavaScript 스택을 사용하여 전체 스택 애플리케이션을 만드는 방법을 살펴보겠습니다. 카우치베이스 NoSQL. 기술의 시작 문자가 모두 자음이기 때문에 약자로 표기하지 않겠습니다.
우리가 구축하는 애플리케이션에는 매우 단순한 데이터 모델이 있습니다. 사람 정보와 주소 정보를 저장하고 주소가 특정 사람과 어떻게 연관되는지 구성할 것입니다.

Hapi 백엔드가 포함된 Node.js는 데이터베이스 내에서 N1QL 및 하위 문서 변형을 사용하는 방법을 보여줄 것입니다. 그리고 Vue.js 프런트엔드를 사용하면 API를 사용할 수 있는 반쯤 매력적인 출구를 확보할 수 있습니다.
쿼리 및 역할 기반 액세스 제어를 위한 Couchbase 구성하기
Couchbase NoSQL 데이터베이스와 통신하는 RESTful API 개발을 시작하려면 먼저 데이터베이스가 올바르게 구성되어 있어야 합니다. 이미 다음과 같이 설치했다고 가정하겠습니다. 카우치베이스 서버 5 이상입니다.
Couchbase를 사용할 준비가 되었으면 데이터를 저장할 버킷을 만들어야 합니다. 이 튜토리얼에서는 다음과 같은 버킷을 참조합니다. 예제하지만 일관성만 있다면 크게 중요하지 않습니다.

이 예제에서는 버킷에 특별한 구성이 필요하지 않습니다.
버킷을 사용할 수 있게 되면, 버킷으로 작업할 수 있는 권한을 가진 사용자를 만들어야 합니다. 역할 기반 액세스 제어(RBAC)를 만드는 방법에 대한 자세한 내용은 이전에 작성한 글을 참조하세요, Couchbase 역할 기반 액세스 제어로 NoSQL 데이터 보호. 계정에는 다음이 필요합니다. 데이터 리더, 데이터 라이터및 쿼리 선택 역할을 추가합니다. 이렇게 하면 데이터베이스에 대한 CRUD 작업을 수행할 수 있을 뿐만 아니라 N1QL 쿼리를 실행할 수 있습니다.
마지막으로 N1QL 쿼리 지원을 위한 인덱스를 준비해야 합니다.

프로덕션 환경에서는 실행하려는 모든 쿼리에 대해 인덱스를 만들어야 합니다. 이 예제에서는 프로토타이핑 인덱스인 기본 인덱스를 사용하겠습니다.
다음 쿼리를 실행하여 인덱스를 생성합니다:
|
1 |
만들기 기본 INDEX 켜기 `예제`; |
기본 인덱스는 성능을 희생하면서 버킷에서 모든 쿼리를 실행할 수 있는 편리함을 제공합니다. 사용자 지정 인덱스는 훨씬 더 나은 성능을 제공합니다.
이 시점에서 개발을 시작할 수 있습니다.
Node.js 및 Hapi 프레임워크로 웹 백엔드 개발하기
Couchbase가 준비되었으므로 이제 Hapi 애플리케이션으로 Node.js 개발을 시작할 수 있습니다. 제 이전 기사를 사용하면 많은 자료가 이월됩니다. 그러나 이 예제에서는 Node.js와 Couchbase의 기능에 대해 좀 더 자세히 살펴볼 것입니다.
Node.js가 설치되어 있다고 가정하고 새 프로젝트를 만들어야 합니다. CLI에서 다음을 실행합니다:
|
1 2 |
npm init -y npm 설치 hapi joi 카우치베이스 uuid --저장 |
위의 명령은 새 프로젝트를 초기화하고 다음을 설치합니다. hapi 패키지, Hapi.js의 joi 데이터 유효성 검사를 위한 카우치베이스 패키지와 카우치베이스와의 상호 작용을 위한 uuid 패키지를 사용하여 고유 문자열을 생성할 수 있습니다.
그런 다음 app.js 파일에 모든 Node.js 코드를 저장합니다. 작업을 시작하려면 프로젝트의 app.js file:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
const 카우치베이스 = require("couchbase"); const Hapi = require("hapi"); const Joi = require("joi"); const UUID = require("uuid"); const 서버 = new Hapi.서버(); const 클러스터 = new 카우치베이스.클러스터("couchbase://localhost"); 클러스터.인증("demo", "123456"); const 버킷 = 클러스터.오픈버킷("예제"); 서버.연결({ 호스트: "localhost", 포트: 3000, 경로: { cors: true } }); 버킷.on("오류", 오류 => { throw 오류; }); 서버.시작(오류 => { 만약(오류) { throw 오류; } 콘솔.로그("에서 듣기" + 서버.정보.uri); }); |
위의 코드는 종속성을 가져오고, 이전 단계에서 지정한 정보를 사용하여 Couchbase 인스턴스에 연결하고, http://localhost:3000 에서 작동하도록 Hapi 서버를 구성합니다.
연결 정보를 정의할 때 CORS(교차 출처 리소스 공유)를 사용하도록 선택했습니다. 이렇게 하면 서로 다른 포트에서 작동하더라도 Vue.js 애플리케이션이 Node.js 애플리케이션과 통신할 수 있습니다. Hapi를 사용한 CORS에 대한 자세한 내용은 이전 기사 제가 쓴 글입니다.
이 시점에서 API에 대한 엔드포인트 경로를 정의할 수 있습니다.
목표는 Couchbase 내에서 사람과 주소에 대한 데이터를 생성하는 것입니다. 현재 이 두 카테고리에 대한 데이터가 존재하지 않으므로 데이터 생성을 수행하는 엔드포인트부터 시작하는 것이 좋습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
서버.경로({ 메서드: "POST", 경로: "/사람", 구성: { 유효성 검사: { 페이로드: { 이름: Joi.문자열().필수(), 성: Joi.문자열().필수(), 유형: Joi.문자열().금지됨().기본값("사람"), 타임스탬프: Joi.any().금지됨().기본값((new 날짜).getTime()) } } }, 핸들러: (요청, 응답) => { var id = UUID.v4(); 버킷.삽입(id, 요청.페이로드, (오류, 결과) => { 만약(오류) { 반환 응답({ 코드: 오류.코드, 메시지: 오류.메시지 }).코드(500); } 요청.페이로드.id = id; 응답(요청.페이로드); }); } }); |
위의 코드는 POST 요청을 수락하는 엔드포인트를 생성합니다. 요청과 함께 전송된 JSON 페이로드가 유효성 검사 로직의 기준을 충족한다고 가정하면 핸들러 가 사용됩니다. 고유 ID가 생성되고 페이로드는 생성된 ID로 저장됩니다. 성공하면 해당 아이디가 포함된 페이로드가 클라이언트로 반환됩니다.
주소를 만들 때도 비슷한 로직을 사용할 수 있습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
서버.경로({ 메서드: "POST", 경로: "/주소", 구성: { 유효성 검사: { 페이로드: { 도시: Joi.문자열().필수(), 상태: Joi.문자열().필수(), 유형: Joi.문자열().금지됨().기본값("주소"), 타임스탬프: Joi.any().금지됨().기본값((new 날짜).getTime()) } } }, 핸들러: (요청, 응답) => { var id = UUID.v4(); 버킷.삽입(id, 요청.페이로드, (오류, 결과) => { 만약(오류) { 반환 응답({ 코드: 오류.코드, 메시지: 오류.메시지 }).코드(500); } 요청.페이로드.id = id; 응답(요청.페이로드); }); } }); |
주소에 대한 유효성 검사 로직은 약간 다르지만 다른 모든 것은 동일하게 유지됩니다. 이 로직은 POST 요청이 있는 거의 모든 생성 엔드포인트에 동일하게 적용될 수 있습니다.
카우치베이스에서 사용할 수 있는 문서를 사용하면 해당 문서에 대한 쿼리를 시도할 수 있습니다. 다음 중 하나를 찾는 전문 쿼리를 만드는 것이 좋습니다. 사람 문서 또는 주소 문서에 추가합니다. 이를 위해 N1QL을 사용하겠습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
서버.경로({ 메서드: "GET", 경로: "/주소", 핸들러: (요청, 응답) => { var 문 = "SELECT META(address).id, address.* FROM example AS address WHERE address.type = 'address'"; var 쿼리 = 카우치베이스.N1qlQuery.fromString(문); 버킷.쿼리(쿼리, (오류, 결과) => { 만약(오류) { 반환 응답({ 코드: 오류.코드, 메시지: 오류.메시지 }).코드(500); } 응답(결과); }); } }); |
위의 경로는 모든 문서와 문서 키에 다음과 같은 속성이 포함되어 있는 한 모든 문서와 해당 문서 키를 가져오는 N1QL 쿼리를 사용합니다. 유형 와 같은 주소.
마찬가지로 다음과 같은 경우에도 동일한 작업을 수행할 수 있습니다. 사람 문서:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
서버.경로({ 메서드: "GET", 경로: "/사람", 핸들러: (요청, 응답) => { var 문 = "SELECT META(person).id, person.* FROM example AS person WHERE person.type = 'person'"; var 쿼리 = 카우치베이스.N1qlQuery.fromString(문); 버킷.쿼리(쿼리, (오류, 결과) => { 만약(오류) { 반환 응답({ 코드: 오류.코드, 메시지: 오류.메시지 }).코드(500); } 응답(결과); }); } }); |
그러나 이는 단순히 문서를 기준으로 쿼리하는 것만으로는 지루합니다. 유형 속성입니다. 두 유형 간의 관계를 설정해야 할 것입니다.
여기서의 아이디어는 사람 문서에 연결된 모든 주소의 ID를 포함하는 배열을 만들 수 있습니다. 전체 문서를 가져와서 배열을 만들거나 업데이트한 다음 다시 저장하는 대신 데이터베이스에서 직접 하위 문서 변형을 수행하겠습니다.
다음 엔드포인트를 예로 들어보겠습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
서버.경로({ 메서드: "PUT", 경로: "/사람/주소/{개인ID}", 구성: { 유효성 검사: { 페이로드: { addressid: Joi.문자열().필수() } } }, 핸들러: (요청, 응답) => { 버킷.mutateIn(요청.매개변수.personid).배열 추가("주소", 요청.페이로드.addressid, true).실행((오류, 결과) => { 만약(오류) { 반환 응답({ 코드: 오류.코드, 메시지: 오류.메시지 }).코드(500); } 버킷.get(요청.매개변수.personid, (오류, 결과) => { 만약(오류) { 반환 응답({ 코드: 오류.코드, 메시지: 오류.메시지 }).코드(500); } 응답(결과.값); }); }); } }); |
위의 엔드포인트는 모든 요청에 경로 매개변수와 페이로드가 존재할 것으로 예상합니다. 경로 매개 변수는 사람 문서와 페이로드에는 주소 문서.
다음을 사용하여 mutateIn 메서드를 사용하면 변경할 문서와 변경해야 하는 프로퍼티의 경로를 제공할 수 있습니다. 이 경우 사람 문서가 변경되고, 값을 추가할 것입니다. 주소 배열을 사용합니다. 만약 주소 속성이 존재하지 않더라도 생성될 것이니 걱정하지 마세요.
변경이 발생하면 변경한 전체 문서를 내려서 클라이언트에 반환합니다.
이제 데이터에 대해 더 흥미로운 N1QL 쿼리를 수행할 수 있습니다. 이 수정된 수집용 엔드포인트를 확인하세요. 사람 문서:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
서버.경로({ 메서드: "GET", 경로: "/사람", 핸들러: (요청, 응답) => { var 문 = "SELECT META(person).id, person.firstname, person.lastname, (SELECT address.city, address.state FROM example AS address USE KEYS person.addresses) AS addresses FROM example AS person WHERE person.type = 'person'"; var 쿼리 = 카우치베이스.N1qlQuery.fromString(문); 버킷.쿼리(쿼리, (오류, 결과) => { 만약(오류) { 반환 응답({ 코드: 오류.코드, 메시지: 오류.메시지 }).코드(500); } 응답(결과); }); } }); |
이제 하위 쿼리를 수행합니다. 주소 ID 값의 배열은 그다지 유용하지 않기 때문에 단순한 쿼리를 수행하는 것이 아닙니다. 대신 하위 쿼리에서는 해당 ID 값을 로드하여 결과에 실제 주소가 포함되도록 합니다.
멋지지 않나요?
마지막 엔드포인트로 RESTful API를 마무리해 보겠습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
서버.경로({ 메서드: "GET", 경로: "/주소/{주소ID}", 핸들러: (요청, 응답) => { 버킷.get(요청.매개변수.addressid, (오류, 결과) => { 만약(오류) { 반환 응답({ 코드: 오류.코드, 메시지: 오류.메시지 }).코드(500); } 응답(결과.값); }); } }); |
위의 엔드포인트를 사용하면 문서 키를 기반으로 특정 주소 하나를 반환할 수 있습니다.
API가 생성되면 Postman 또는 유사한 도구를 사용하여 쉽게 테스트할 수 있습니다. 하지만 여기서는 Vue.js를 사용하여 프론트엔드를 만들겠습니다.
Vue.js로 클라이언트 프론트엔드 만들기
프론트엔드의 기본 개념은 방금 만든 백엔드에 HTTP 요청을 하는 것입니다. 대부분의 작업은 요청, 데이터 바인딩, UI의 전반적인 매력에 관한 것입니다.
Vue.js를 처음 사용하는 경우 Vue CLI를 구했는지 확인하세요. 새 디렉토리에서 Vue CLI를 사용하여 다음을 실행합니다:
|
1 |
vue init 웹팩 프론트엔드 |
위의 명령은 Vue.js에 대한 스캐폴딩 프로세스를 시작합니다. 선택 아니요 모든 기능을 사용하지 않을 것이므로 요청된 모든 기능을 사용할 수 없습니다. 독립형 프로젝트(컴파일러 및 런타임)와 런타임 전용 프로젝트의 경우 이 예제에서는 중요하지 않습니다.
스캐폴딩이 완료되면 다음 명령을 실행합니다:
|
1 2 |
cd 프론트엔드 npm 설치 |
위의 명령은 기본 프로젝트에 필요한 모든 종속성을 다운로드합니다. 하지만 Vue.js로 HTTP 요청을 하기 위해서는 종속성이 필요합니다. CLI에서 다음을 실행합니다:
|
1 |
npm 설치 axios --저장 |
이 프로젝트는 axios 패키지를 사용하세요. axios와 Vue.js로 HTTP 요청을 만드는 방법에 대한 자세한 내용은 이전에 작성한 튜토리얼을 참조하세요, Vue.js 웹 애플리케이션에서 HTTP를 통해 원격 API 데이터 사용.
프로젝트 내에는 src/App.vue 파일에 저장합니다. 간단하게 설명하기 위해 단일 페이지와 단일 파일 애플리케이션이 될 것입니다. 스캐폴드와 함께 생성된 다른 컴포넌트는 무시하세요.
HTML 마크업과 JavaScript 로직을 추가하기 전에 다음을 포함하겠습니다. 부트스트랩 를 테마 프레임워크로 사용합니다. 프로젝트의 index.html 파일을 열고 다음과 같이 만듭니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html> <head> <메타 문자셋="utf-8"> <title>vue-프로젝트</title> <링크 rel="스타일시트" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /> </head> <body> <div id="app"></div> <!-- built 파일 will be 자동 주입 --> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </body> </html> |
위의 내용은 대부분 부트스트랩 시작하기 문서. 이제 코딩을 시작하면 src/App.vue 파일을 사용하면 좀 더 매력적으로 보일 것입니다.
대부분의 Vue 프로젝트 파일과 마찬가지로, 이 파일에는 <template>, <script>및 <style> 블록. 우리의 <style> 블록에는 특별히 추가된 것이 없으므로 프로젝트의 src/App.vue 파일을 열고 다음을 포함하세요:
|
1 2 3 4 5 6 7 8 9 |
<style> #app { 글꼴 가족: 'Avenir', 헬베티카, Arial, 산세리프; -웹킷 글꼴 스무딩: 앤티앨리어싱; -moz-osx-font-smoothing: 그레이 스케일; 색상: #2c3e50; margin-top: 30px; } </style> |
대부분의 작업은 나머지 두 개의 코드 블록에서 이루어집니다. 간단하게 하기 위해 로직부터 시작해서 UI로 마무리하겠습니다.
프로젝트의 src/App.vue 파일에 다음 자바스크립트 코드를 포함합니다:
|
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
<script> 가져오기 axios 에서 "axios"; 내보내기 기본값 { 이름: 'app', 데이터() { 반환 { 입력: { 사람: { 이름: "", 성: "" }, 주소: { 도시: "", 상태: "" }, addressid: "" }, 사람들: [], 주소: [] } }, 탑재() { axios({ 메서드: "GET", URL: "http://localhost:3000/people" }).다음(결과 => { 이.사람들 = 결과.데이터; }); axios({ 메서드: "GET", URL: "http://localhost:3000/addresses" }).다음(결과 => { 이.주소 = 결과.데이터; }); }, 메소드: { createPerson() { 만약(이.입력.사람.이름 != "" && 이.입력.사람.성 != "") { axios({ 메서드: "POST", URL: "http://localhost:3000/person", 데이터: 이.입력.사람, 헤더: { "콘텐츠 유형": "application/json" }}).다음(결과 => { 이.사람들.push(결과.데이터); 이.입력.사람.이름 = ""; 이.입력.사람.성 = ""; }); } }, createAddress() { 만약(이.입력.주소.도시 != "" && 이.입력.주소.상태 != "") { axios({ 메서드: "POST", URL: "http://localhost:3000/address", 데이터: 이.입력.주소, 헤더: { "콘텐츠 유형": "application/json" }}).다음(결과 => { 이.주소.push(결과.데이터); 이.입력.주소.도시 = ""; 이.입력.주소.상태 = ""; }); } }, 링크 주소(personid) { 만약(이.입력.addressid != 정의되지 않음 && personid != "") { axios({ 메서드: "PUT", URL: "http://localhost:3000/person/address/" + personid, 데이터: { addressid: 이.입력.addressid }, 헤더: { "콘텐츠 유형": "application/json" }}).다음(결과 => { 에 대한(let i = 0; i < 이.사람들.길이; i++) { 만약(이.사람들[i].id == personid) { 만약(이.사람들[i].주소 == 정의되지 않음) { 이.사람들[i].주소 = []; } axios({ 메서드: "GET", URL: "http://localhost:3000/address/" + 이.입력.addressid }).다음(결과 => { 이.사람들[i].주소.push(결과.데이터); 이.입력.addressid = ""; }); } } }); } } } } </script> |
위의 내용에는 많은 일이 일어나고 있으므로 이를 세분화하여 설명하겠습니다.
우리가 추가하는 첫 번째 핵심 로직은 데이터 초기화에 관한 것입니다. 데이터 초기화는 데이터 메서드를 사용하면 이 특정 파일 전체에서 사용되는 변수를 초기화할 수 있습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
데이터() { 반환 { 입력: { 사람: { 이름: "", 성: "" }, 주소: { 도시: "", 상태: "" }, addressid: "" }, 사람들: [], 주소: [] } }, |
에서 데이터 메서드, 즉 입력 객체는 UI의 양식에 바인딩됩니다. 우리의 경우 두 개의 폼이 있는데 하나는 사람 그리고 하나는 주소. 기본적으로 값은 공백으로 설정합니다. 또한 사람들 및 주소 는 Node.js API에서 가져옵니다.
변수를 초기화한 후에는 서버에서 일부 데이터를 로드해야 합니다. 이 작업은 탑재 메서드를 사용합니다.
|
1 2 3 4 5 6 7 8 |
탑재() { axios({ 메서드: "GET", URL: "http://localhost:3000/people" }).다음(결과 => { 이.사람들 = 결과.데이터; }); axios({ 메서드: "GET", URL: "http://localhost:3000/addresses" }).다음(결과 => { 이.주소 = 결과.데이터; }); }, |
애플리케이션이 로드되면 사람에 대한 요청과 주소에 대한 요청이 이루어집니다.
그러면 HTML에서 호출할 수 있는 메소드 목록으로 연결됩니다. 메소드의 createPerson 메서드는 개인 양식에서 데이터를 가져와 저장할 수 있도록 API로 전송합니다. 마찬가지로 createAddress 메서드는 주소 정보를 사용하여 동일한 작업을 수행합니다.
그리고 링크 주소 방법은 조금 다릅니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
링크 주소(personid) { 만약(이.입력.addressid != 정의되지 않음 && personid != "") { axios({ 메서드: "PUT", URL: "http://localhost:3000/person/address/" + personid, 데이터: { addressid: 이.입력.addressid }, 헤더: { "콘텐츠 유형": "application/json" }}).다음(결과 => { 에 대한(let i = 0; i < 이.사람들.길이; i++) { 만약(이.사람들[i].id == personid) { 만약(이.사람들[i].주소 == 정의되지 않음) { 이.사람들[i].주소 = []; } axios({ 메서드: "GET", URL: "http://localhost:3000/address/" + 이.입력.addressid }).다음(결과 => { 이.사람들[i].주소.push(결과.데이터); 이.입력.addressid = ""; }); } } }); } } |
그리고 링크 주소 메서드는 특정 사람 ID와 특정 주소 ID를 모두 가져와 하위 문서 API 엔드포인트로 전송합니다. 완료되면 UI에 표시하기 위해 로컬 변수의 정보를 업데이트합니다.
그러면 애플리케이션 파일의 HTML 부분으로 이동합니다. 애플리케이션 파일의 <template> 블록에 다음과 같은 내용이 있어야 합니다:
|
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<템플릿> <div id="app"> <div 클래스="컨테이너"> <div 클래스="row"> <div 클래스="COL-MD-6"> <div 클래스="잘"> <양식> <div 클래스="form-group"> <레이블 에 대한="이름">먼저 이름</레이블> <입력 유형="text" v-모델="입력.사람.이름" 클래스="form-control" id="이름" 플레이스홀더="이름"> </div> <div 클래스="form-group"> <레이블 에 대한="성">마지막 이름</레이블> <입력 유형="text" v-모델="입력.사람.성" 클래스="form-control" id="성" 플레이스홀더="성"> </div> <버튼 유형="버튼" v-on:클릭="createPerson()" 클래스="btn btn-default">저장</버튼> </양식> </div> </div> <div 클래스="COL-MD-6"> <div 클래스="잘"> <양식> <div 클래스="form-group"> <레이블 에 대한="city">도시</레이블> <입력 유형="text" v-모델="입력.주소.도시" 클래스="form-control" id="city" 플레이스홀더="City"> </div> <div 클래스="form-group"> <레이블 에 대한="state">상태</레이블> <입력 유형="text" v-모델="입력.주소.상태" 클래스="form-control" id="state" 플레이스홀더="State"> </div> <버튼 유형="버튼" v-on:클릭="createAddress()" 클래스="btn btn-default">저장</버튼> </양식> </div> </div> </div> <div 클래스="row"> <div 클래스="COL-MD-12"> <ul 클래스="list-group"> <li v-에 대한="(사람, 색인)의 사람" 클래스="목록-그룹-아이템"> {{ 사람.이름 }} {{ 사람.성 }} - <span v-에 대한="(주소, 색인) in person.addresses"> {{ 주소.도시 }}, {{ 주소.상태 }} / </span> <p> <양식> <div v-에 대한="(주소, 색인) 주소의 주소"> <입력 유형="라디오" 이름="addressid" v-바인드:값="address.id" v-모델="input.addressid"> {{ 주소.도시 }}, {{ 주소.상태 }} </div> <버튼 유형="버튼" v-on:클릭="linkAddress(person.id)" 클래스="btn btn-default">저장</버튼> </양식> </p> </li> </ul> </div> </div> </div> </div> </템플릿> |
위의 HTML은 대부분 부트스트랩 상용구입니다. 이전에 부트스트랩으로 작업해 본 적이 있다면 준비해야 할 것이 많다는 것을 알 것입니다.
다음 섹션으로 이동합니다:
|
1 2 3 4 5 6 7 8 9 10 11 |
<양식> <div 클래스="form-group"> <레이블 에 대한="이름">먼저 이름</레이블> <입력 유형="text" v-모델="입력.사람.이름" 클래스="form-control" id="이름" 플레이스홀더="이름"> </div> <div 클래스="form-group"> <레이블 에 대한="성">마지막 이름</레이블> <입력 유형="text" v-모델="입력.사람.성" 클래스="form-control" id="성" 플레이스홀더="성"> </div> <버튼 유형="버튼" v-on:클릭="createPerson()" 클래스="btn btn-default">저장</버튼> </양식> |
다음 사항에 유의하세요. 입력 객체가 이제 양식 요소에 바인딩됩니다. 이것은 양방향 데이터 바인딩입니다.
이 특정 양식에 대해 양식 버튼을 누르면 createPerson 메서드가 호출됩니다. 다른 양식 요소도 동일하게 작동합니다.
UI의 주요 부분에는 서버에서 검색된 데이터 목록이 있습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<ul 클래스="list-group"> <li v-에 대한="(사람, 색인)의 사람" 클래스="목록-그룹-아이템"> {{ 사람.이름 }} {{ 사람.성 }} - <span v-에 대한="(주소, 색인) in person.addresses"> {{ 주소.도시 }}, {{ 주소.상태 }} / </span> <p> <양식> <div v-에 대한="(주소, 색인) 주소의 주소"> <입력 유형="라디오" 이름="addressid" v-바인드:값="address.id" v-모델="input.addressid"> {{ 주소.도시 }}, {{ 주소.상태 }} </div> <버튼 유형="버튼" v-on:클릭="linkAddress(person.id)" 클래스="btn btn-default">저장</버튼> </양식> </p> </li> </ul> |
사람, 서버 측 N1QL 쿼리의 확장된 주소 정보, 하위 문서 요청을 위한 라디오 버튼 상호 작용을 나열하고 있습니다.
UI가 로직 레이어에 바인딩되는 방식 덕분에 Vue.js를 사용하면 이 모든 작업을 쉽게 수행할 수 있습니다.
결론
지금까지 자바스크립트 기술로만 구성된 풀 스택 애플리케이션을 만드는 방법을 살펴보았습니다. API 백엔드 레이어에는 Node.js와 Hapi.js 프레임워크를, 프론트엔드 웹 브라우저 레이어에는 Vue.js 프레임워크를 사용했습니다. 프론트엔드는 백엔드에서 데이터를 소비하고, 백엔드는 우리의 카우치베이스 NoSQL 데이터베이스.
애플리케이션을 매우 모듈식으로 만들었기 때문에 각 구성 요소를 다른 기술로 교체할 수 있습니다. Node.js를 Java나 다른 것으로 바꿀 수 있고, Vue.js를 Angular와 같은 다른 것으로 바꿀 수도 있습니다. Golang과 Angular로 전체 스택을 사용하는 방법을 알아보려면 제가 작성한 이 튜토리얼을 확인하세요, Golang, Angular, NoSQL로 풀 스택 영화 데이터베이스 구축하기.
Node.js와 함께 Couchbase를 사용하는 방법에 대한 자세한 내용은 카우치베이스 개발자 포털.