LoopBack Do It: 당신이 꿈꾸던 노드 API 프레임워크의 연습
게시 됨: 2022-03-11애플리케이션 개발을 위한 Node.js의 인기가 높아지고 있다는 것은 말할 필요도 없습니다. eBay는 2011년부터 프로덕션 Node API 서비스를 실행해 왔습니다. PayPal은 Node.js에서 프론트엔드를 적극적으로 재구축하고 있습니다. Walmart의 모바일 사이트는 트래픽 측면에서 가장 큰 Node 애플리케이션이 되었습니다. 2014년 추수감사절 주말에 Walmart 서버는 15억 건의 요청을 처리했으며 그 중 70%는 모바일을 통해 전달되었으며 Node.js로 구동되었습니다. 개발 측면에서 노드 패키지 관리자(npm)는 계속해서 빠르게 성장하고 있으며 최근에는 150,000개의 호스트된 모듈을 초과했습니다.
Ruby에는 Rails가 있고 Python에는 Django가 있지만 Node의 주요 애플리케이션 개발 프레임워크는 아직 확립되지 않았습니다. 그러나 힘을 얻고 있는 강력한 경쟁자가 있습니다. 바로 LoopBack, 캘리포니아 San Mateo, StrongLoop 회사에서 구축한 오픈 소스 API 프레임워크입니다. StrongLoop은 현존하는 가장 인기 있는 Node 프레임워크 중 하나인 Express의 오랜 유지 관리자는 말할 것도 없고 최신 Node 버전에 중요한 기여자입니다.
모든 것을 실습으로 전환하고 예제 애플리케이션을 구축하여 LoopBack과 기능을 자세히 살펴보겠습니다.
LoopBack이란 무엇이며 Node에서 어떻게 작동합니까?
LoopBack은 API를 생성하고 백엔드 데이터 소스와 연결하기 위한 프레임워크입니다. Express를 기반으로 구축되어 데이터 모델 정의를 사용하고 모든 클라이언트에서 호출할 수 있는 완전한 기능의 종단 간 REST API를 쉽게 생성할 수 있습니다.
LoopBack은 내장 클라이언트 API Explorer 와 함께 제공됩니다. 이를 사용하면 작업 결과를 더 쉽게 볼 수 있고 예제에서 API 자체를 빌드하는 데 집중할 수 있습니다.
물론 따라 하려면 컴퓨터에 Node가 설치되어 있어야 합니다. 여기에서 받으세요. npm이 함께 제공되므로 필요한 패키지를 쉽게 설치할 수 있습니다. 시작하자.
스켈레톤 생성
우리의 응용 프로그램은 선물이나 더 이상 필요하지 않은 물건을 필요할 수도 있는 누군가에게 기부하려는 사람들을 관리합니다. 따라서 사용자는 기증자와 수신자가 됩니다. 기부자는 새 선물을 만들고 선물 목록을 볼 수 있습니다. 수신자는 모든 사용자의 선물 목록을 볼 수 있으며 청구되지 않은 선물을 청구할 수 있습니다. 물론 Donors와 Receiver를 동일한 엔티티(User)에 대해 별도의 역할로 구축할 수 있지만 LoopBack에서 관계를 구축하는 방법을 볼 수 있도록 이들을 분리해 보겠습니다. 이 획기적인 응용 프로그램의 이름은 Givesomebody 입니다.
npm을 통해 StrongLoop 명령줄 도구를 설치합니다.
$ npm install -g strongloop
그런 다음 LoopBack의 애플리케이션 생성기를 실행하십시오.
$ slc loopback _-----_ | | .--------------------------. |--(o)--| | Let's create a LoopBack | `--------- | application! | ( _U`_ ) '--------------------------' /___A___\ | ~ | __'.___.'__ ` |° Y ` ? What's the name of your application? Givesomebody
모델을 추가해 보겠습니다. 첫 번째 모델은 Gift라고 합니다. LoopBack은 데이터 소스와 기본 클래스를 요청할 것입니다. 아직 데이터 소스를 설정하지 않았기 때문에 db (memory)
를 넣을 수 있습니다. 기본 클래스는 자동 생성된 모델 클래스이며 이 경우 PersistedModel
을 사용하려고 합니다. 이미 일반적인 CRUD 메서드가 모두 포함되어 있기 때문입니다. 다음으로 LoopBack은 REST를 통해 모델을 노출해야 하는지(yes), REST 서비스 이름을 묻습니다. 여기에서 Enter 키를 눌러 기본값을 사용합니다. 이 기본값은 단순히 모델 이름의 복수형입니다(이 경우에는 gifts
).
$ slc loopback:model ? Enter the model name: Gift ? Select the data-source to attach Gift to: (Use arrow keys) ❯ db (memory) ? Select model's base class: (Use arrow keys) Model ❯ PersistedModel ? Expose Gift via the REST API? (Y/n) Yes ? Custom plural form (used to build REST URL):
마지막으로 속성의 이름, 데이터 유형, 필수/비필수 플래그를 제공합니다. 선물에는 다음과 같은 name
및 description
속성이 있습니다.
Let's add some Gift properties now. Enter an empty property name when done. ? Property name: name invoke loopback:property ? Property type: (Use arrow keys) ❯ string ? Required? (y/N)Yes
속성 정의가 완료되었음을 나타내려면 빈 속성 이름을 입력하십시오.
모델 생성기는 애플리케이션의 common/models
에서 모델을 정의하는 두 개의 파일( gift.json
및 gift.js
)을 생성합니다. JSON 파일은 엔터티에 대한 모든 메타데이터(속성, 관계, 유효성 검사, 역할 및 메서드 이름)를 지정합니다. JavaScript 파일은 추가 동작을 정의하고 특정 작업(예: 생성, 업데이트 또는 삭제) 전후에 호출될 원격 후크를 지정하는 데 사용됩니다.
다른 두 모델 엔터티는 Donor 및 Receiver 모델입니다. 이번에는 User
를 기본 클래스로 두는 것을 제외하고는 동일한 프로세스를 사용하여 생성할 수 있습니다. username
, password
, email
과 같은 속성을 즉시 제공합니다. 예를 들어 이름과 국가만 추가하여 전체 엔터티를 가질 수 있습니다. Receiver의 경우 배송 주소도 추가하려고 합니다.
프로젝트 구조
생성된 프로젝트 구조를 살펴보겠습니다.
세 가지 기본 디렉토리는 다음과 같습니다. - /server
– 노드 응용 프로그램 스크립트 및 구성 파일이 포함되어 있습니다. - /client
– .js, .html, .css 및 기타 모든 정적 파일을 포함합니다. - /common
– 이 폴더는 서버와 클라이언트 모두에 공통입니다. 모델 파일은 여기로 이동합니다.
다음은 LoopBack 문서에서 가져온 각 디렉토리의 내용에 대한 자세한 분석입니다.
파일 또는 디렉토리 | 설명 | 코드에서 액세스하는 방법 |
---|---|---|
최상위 애플리케이션 디렉토리 | ||
package.json | 표준 npm 패키지 사양. package.json 참조 | 해당 없음 |
/server 디렉토리 - 노드 애플리케이션 파일 | ||
server.js | 주요 응용 프로그램 파일. | 해당 없음 |
config.json | 애플리케이션 설정. config.json을 참조하십시오. | app.get('setting-name') |
datasources.json | 데이터 소스 구성 파일. datasources.json을 참조하십시오. 예를 들어 새 데이터 원본 만들기 를 참조하십시오 . | app.datasources['datasource-name'] |
model-config.json | 모델 구성 파일. model-config.json을 참조하십시오. 자세한 내용은 데이터 소스에 모델 연결 . | 해당 없음 |
middleware.json | 미들웨어 정의 파일. 자세한 내용은 미들웨어 정의를 참조하세요. | 해당 없음 |
/boot 디렉토리 | 초기화 및 설정을 수행하는 스크립트를 추가합니다. 부팅 스크립트를 참조하십시오. | 스크립트는 알파벳 순서로 자동으로 실행됩니다. |
/client 디렉토리 - 클라이언트 애플리케이션 파일 | ||
README.md | LoopBack 생성기는 마크다운 형식으로 빈 README 파일을 생성합니다. | 해당 없음 |
다른 | HTML, CSS, 클라이언트 JavaScript 파일을 추가합니다. | |
/common 디렉토리 - 공유 애플리케이션 파일 | ||
/models 디렉토리 | 커스텀 모델 파일:
| 마디:myModel = app.models.myModelName |
관계 구축
이 예에서는 모델링할 몇 가지 중요한 관계가 있습니다. 기증자는 많은 선물을 기부할 수 있으며, 이는 기증자가 많은 선물을 가지고 있다는 관계를 제공합니다. Receiver는 또한 많은 Gift를 받을 수 있으므로 Receiver에는 많은 Gift가 있다는 관계도 있습니다. 반면 Gift는 Donor에 속하며 Receiver가 수락하기로 선택한 경우 Receiver에도 속할 수 있습니다. 이것을 LoopBack 언어에 넣어보자.
$ slc loopback:relation ? Select the model to create the relationship from: Donor ? Relation type: has many ? Choose a model to create a relationship with: Gift ? Enter the property name for the relation: gifts ? Optionally enter a custom foreign key: ? Require a through model? No
통해 모델이 없다는 점에 유의하십시오. 우리는 선물에 대한 참조를 보유하고 있습니다.
Receiver에 대해 위의 절차를 반복하고 Gift 에 관계에 두 개를 추가하면 백엔드 측에서 모델 설계를 완료합니다. LoopBack은 다음과 같은 간단한 대화 상자를 통해 방금 수행한 작업을 정확하게 표현하기 위해 모델의 JSON 파일을 자동으로 업데이트합니다.
// common/models/donor.json ... "relations": { "gifts": { "type": "hasMany", "model": "Gift", "foreignKey": "" } }, ...
데이터 소스 추가
이제 실제 데이터 소스를 연결하여 모든 애플리케이션 데이터를 저장하는 방법을 살펴보겠습니다. 이 예에서는 MongoDB를 사용하지만 LoopBack에는 Oracle, MySQL, PostgreSQL, Redis 및 SQL Server와 연결하는 모듈이 있습니다.
먼저 커넥터를 설치합니다.
$ npm install --save loopback-connector-mongodb
그런 다음 프로젝트에 데이터 소스를 추가합니다.
$ slc loopback:datasource ? Enter the data-source name: givesomebody ? Select the connector for givesomebody: MongoDB (supported by StrongLoop)
다음 단계는 server/datasources.json
에서 데이터 소스를 구성하는 것입니다. 로컬 MongoDB 서버에 대해 다음 구성을 사용합니다.
... "givesomebody": { "name": "givesomebody", "connector": "mongodb", "host": "localhost", "port": 27017, "database": "givesomebody", "username": "", "password": "" } ...
마지막으로 server/model-config.json
을 열고 데이터베이스에 유지하려는 모든 엔터티의 datasource
를 "givesomebody"
로 변경합니다.
{ ... "User": { "dataSource": "givesomebody" }, "AccessToken": { "dataSource": "givesomebody", "public": false }, "ACL": { "dataSource": "givesomebody", "public": false }, "RoleMapping": { "dataSource": "givesomebody", "public": false }, "Role": { "dataSource": "givesomebody", "public": false }, "Gift": { "dataSource": "givesomebody", "public": true }, "Donor": { "dataSource": "givesomebody", "public": true }, "Receiver": { "dataSource": "givesomebody", "public": true } }
REST API 테스트
우리가 지금까지 구축한 것을 볼 시간입니다! 우리는 방금 만든 서비스의 클라이언트로 사용할 수 있는 멋진 내장 도구인 API Explorer 를 사용할 것입니다. REST API 호출을 테스트해 봅시다.
별도의 창에서 다음을 사용하여 MongoDB를 시작합니다.
$ mongod
다음을 사용하여 애플리케이션을 실행합니다.
$ node .
브라우저에서 http://localhost:3000/explorer/
로 이동합니다. 사용 가능한 작업 목록과 함께 엔터티를 볼 수 있습니다. POST /Donors
호출로 Donor를 하나 추가해 보세요.
API 탐색기 는 매우 직관적입니다. 노출된 방법 중 하나를 선택하면 해당 모델 스키마가 오른쪽 하단에 표시됩니다. data
텍스트 영역에서 사용자 정의 HTTP 요청을 작성할 수 있습니다. 요청이 완료되면 "Try it out" 버튼을 클릭하면 서버의 응답이 아래에 표시됩니다.

사용자 인증
위에서 언급했듯이 LoopBack과 함께 미리 빌드된 엔터티 중 하나는 User 클래스입니다. 사용자는 로그인 및 로그아웃 방법을 가지고 있으며 특정 사용자의 토큰을 유지하는 AccessToken 엔터티에 바인딩될 수 있습니다. 사실, 완전한 사용자 인증 시스템은 즉시 사용할 수 있습니다. API Explorer 를 통해 /Donors/login
을 호출하려고 하면 다음과 같은 응답을 받습니다.
{ "id": "9Kvp4zc0rTrH7IMMeRGwTNc6IqNxpVfv7D17DEcHHsgcAf9Z36A3CnPpZJ1iGrMS", "ttl": 1209600, "created": "2015-05-26T01:24:41.561Z", "userId": "" }
id
는 실제로 AccessToken의 값이며 데이터베이스에서 자동으로 생성되고 유지됩니다. 여기에서 볼 수 있듯이 액세스 토큰을 설정하고 각 후속 요청에 사용할 수 있습니다.
원격 방법
원격 메서드는 사용자 지정 REST 끝점을 통해 노출되는 모델의 정적 메서드입니다. 원격 메소드는 LoopBack의 표준 모델 REST API에서 제공하지 않는 작업을 수행하는 데 사용할 수 있습니다.
기본적으로 제공되는 CRUD 메서드 외에도 원하는 만큼 사용자 지정 메서드를 추가할 수 있습니다. 모두 [model].js
파일로 이동해야 합니다. 우리의 경우 선물이 이미 예약되었는지 확인하는 원격 메서드와 예약되지 않은 모든 선물을 나열하는 원격 메서드를 Gift 모델에 추가해 보겠습니다.
먼저 reserved
라는 모델에 속성을 추가해 보겠습니다. 다음을 gift.json
의 속성에 추가하기만 하면 됩니다.
... "reserved": { "type": "boolean" } ...
gift.js
의 원격 메소드는 다음과 같아야 합니다.
module.exports = function(Gift) { // method which lists all free gifts Gift.listFree = function(cb) { Gift.find({ fields: { reserved: false } }, cb); }; // expose the above method through the REST Gift.remoteMethod('listFree', { returns: { arg: 'gifts', type: 'array' }, http: { path: '/list-free', verb: 'get' } }); // method to return if the gift is free Gift.isFree = function(id, cb) { var response; Gift.find({ fields: { id: id } }, function(err, gift) { if (err) return cb(err); if (gift.reserved) response = 'Sorry, the gift is reserved'; else response = 'Great, this gift can be yours'; }); cb(null, response); }; // expose the method through REST Gift.remoteMethod('isFree', { accepts: { arg: 'id', type: 'number' }, returns: { arg: 'response', type: 'string' }, http: { path: '/free', verb: 'post' } }); };
따라서 특정 선물을 사용할 수 있는지 확인하기 위해 클라이언트는 이제 문제의 선물 id
를 전달하는 POST 요청을 /api/Gifts/free
로 보낼 수 있습니다.
원격 후크
때때로 원격 메소드 전후에 어떤 메소드를 실행해야 할 필요가 있습니다. 두 가지 종류의 원격 후크를 정의할 수 있습니다.
-
beforeRemote()
는 원격 메서드보다 먼저 실행됩니다. -
afterRemote()
는 원격 메서드 이후에 실행됩니다.
두 경우 모두 함수를 "연결"하려는 원격 메서드와 일치하는 문자열과 콜백 함수라는 두 가지 인수를 제공합니다. 원격 후크의 대부분은 문자열에 와일드카드가 포함될 수 있으므로 모든 일치 방법에 의해 트리거된다는 것입니다.
우리의 경우에는 새로운 Donor가 생성될 때마다 콘솔에 정보를 출력하는 hook을 설정해 봅시다. 이를 수행하기 위해 donor.js
에 "before create" 후크를 추가합니다.
module.exports = function(Donor) { Donor.beforeRemote('create', function(context, donor, next) { console.log('Saving new donor with name: ', context.req.body.name); next(); }); };
요청은 주어진 context
로 호출되고 미들웨어의 next()
콜백(아래에서 설명)은 후크가 실행된 후에 호출됩니다.
액세스 제어
LoopBack 애플리케이션은 모델을 통해 데이터에 액세스하므로 데이터에 대한 액세스를 제어한다는 것은 모델에 대한 제한을 정의하는 것을 의미합니다. 즉, 누가 또는 무엇을 데이터를 읽고 쓸 수 있는지 지정하거나 모델에서 메소드를 실행할 수 있습니다. LoopBack 액세스 제어는 액세스 제어 목록 또는 ACL에 의해 결정됩니다.
로그인하지 않은 기부자와 받는 사람이 선물을 볼 수 있도록 허용하고 로그인한 기부자만 선물을 만들고 삭제할 수 있도록 합시다.
$ slc loopback:acl
시작하려면 모든 엔드포인트에 대한 모든 사람의 액세스를 거부하겠습니다.
? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: All (match all types) ? Select the role: All users ? Select the permission to apply: Explicitly deny access
다음으로 모든 사람이 선물 모델에서 읽을 수 있도록 허용합니다.
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: Read ? Select the role: All users ? Select the permission to apply: Explicitly grant access
그런 다음 인증된 사용자가 Gifts를 만들 수 있도록 허용하려고 합니다.
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: A single method ? Enter the method name: create ? Select the role: Any authenticated user ? Select the permission to apply: Explicitly grant access
마지막으로 선물 소유자가 변경할 수 있도록 허용합니다.
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: Write ? Select the role: The user owning the object ? Select the permission to apply: Explicitly grant access
이제 gift.json
을 검토할 때 모든 것이 제자리에 있어야 합니다.
"acls": [ { "accessType": "*", "principalType": "ROLE", "principalId": "$everyone", "permission": "DENY" }, { "accessType": "READ", "principalType": "ROLE", "principalId": "$everyone", "permission": "ALLOW" }, { "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "$authenticated", "permission": "ALLOW", "property": "create" } ],
여기서 한 가지 중요한 참고 사항: $authenticated
는 시스템의 모든 사용자(기부자와 수신자 모두)에 해당하는 사전 정의된 역할이지만, 우리는 기부자가 새 선물을 생성할 수만 있도록 허용하고 싶습니다. 따라서 사용자 지정 역할이 필요합니다. Role은 기본적으로 제공되는 또 하나의 엔터티이므로 해당 API 호출을 활용하여 부팅 기능에서 $authenticatedDonor
역할을 만든 다음 pricipalId
에서 gift.json
를 수정하기만 하면 됩니다.
새 파일 server/boot/script.js
를 만들고 다음 코드를 추가해야 합니다.
Role.create({ name: 'authenticatedDonor' }, function(err, role) { if (err) return debug(err); })
RoleMapping 엔터티는 역할을 사용자에 매핑합니다. Role 및 RoleMapping이 모두 REST를 통해 노출되는지 확인하십시오. server/model-config.json
에서 Role 엔터티에 대해 "public"
이 true
로 설정되어 있는지 확인합니다. 그런 다음 donor.js
에서 RoleMapping POST API 호출에서 userID
와 roleID
를 매핑하는 "before create" 후크를 작성할 수 있습니다.
미들웨어
미들웨어에는 REST 엔드포인트에 대한 요청이 있을 때 실행되는 기능이 포함됩니다. LoopBack은 Express를 기반으로 하므로 "미들웨어 단계"라는 하나의 추가 개념과 함께 Express 미들웨어를 사용합니다. 단계는 미들웨어에서 함수가 호출되는 순서를 명확하게 정의하는 데 사용됩니다.
다음은 LoopBack 문서에 제공된 사전 정의된 단계 목록입니다.
- initial - 미들웨어가 실행될 수 있는 첫 번째 지점입니다.
- session - 세션 객체를 준비합니다.
- auth - 인증 및 권한 부여를 처리합니다.
- parse - 요청 본문을 구문 분석합니다.
- route - 애플리케이션 로직을 구현하는 HTTP 경로. Express API app.use, app.route, app.get(및 기타 HTTP 동사)을 통해 등록된 미들웨어는 이 단계의 시작 부분에서 실행됩니다. loopback/server/middleware/rest 또는 loopback-explorer와 같은 하위 앱에도 이 단계를 사용합니다.
- 파일 - 정적 자산을 제공합니다(요청이 여기에서 파일 시스템에 도달함).
- final - 알 수 없는 URL에 대한 오류 및 요청을 처리합니다.
각 단계에는 세 개의 하위 단계가 있습니다. 예를 들어 초기 단계의 하위 단계는 다음과 같습니다.
- 이니셜:전
- 초기의
- 이니셜:후
기본 middleware.json을 간단히 살펴보겠습니다.
{ "initial:before": { "loopback#favicon": {} }, "initial": { "compression": {}, "cors": { "params": { "origin": true, "credentials": true, "maxAge": 86400 } } }, "session": { }, "auth": { }, "parse": { }, "routes": { }, "files": { }, "final": { "loopback#urlNotFound": {} }, "final:after": { "errorhandler": {} } }
초기 단계에서 loopback.favicon()
을 호출합니다( loopback#favicon
은 해당 호출에 대한 미들웨어 ID입니다). 그런 다음 타사 npm 모듈 compression
및 cors
가 호출됩니다(매개변수 포함 또는 제외). 마지막 단계에서 두 번의 호출이 더 있습니다. urlNotFound
는 LoopBack 호출이고 errorhandler
는 타사 모듈입니다. 이 예제는 많은 내장 호출이 외부 npm 모듈처럼 사용될 수 있음을 보여주어야 합니다. 물론, 우리는 항상 자체 미들웨어를 만들고 이 JSON 파일을 통해 호출할 수 있습니다.
loopback-boot
마무리하기 위해 응용 프로그램을 초기화하는 boot()
함수를 내보내는 모듈을 언급하겠습니다. server/server.js
에서 애플리케이션을 부트스트랩하는 다음 코드를 찾을 수 있습니다.
boot(app, __dirname, function(err) { if (err) throw err; // start the server if `$ node server.js` if (require.main === module) app.start(); });
이 스크립트는 server/boot
폴더를 검색하고 거기에서 찾은 모든 스크립트를 알파벳 순서로 로드합니다. 따라서 server/boot
에서 시작할 때 실행되어야 하는 스크립트를 지정할 수 있습니다. 한 가지 예는 API Explorer 를 실행하는 explorer.js
이며, API 테스트에 사용한 클라이언트입니다.
결론
떠나기 전에 slc
명령줄 도구의 대안으로 사용할 수 있는 그래픽 UI인 StrongLoop Arc에 대해 언급하고 싶습니다. 여기에는 Node 애플리케이션을 구축, 프로파일링 및 모니터링하기 위한 도구도 포함됩니다. 커맨드 라인의 팬이 아닌 사람들을 위해 이것은 확실히 시도해 볼 가치가 있습니다. 그러나 StrongLoop Arc는 더 이상 사용되지 않으며 해당 기능은 IBM API Connect Developer Toolkit에 통합됩니다.
일반적으로 LoopBack은 상자에서 많은 것을 얻을 수 있기 때문에 많은 수동 작업을 절약할 수 있습니다. 이를 통해 애플리케이션별 문제 및 비즈니스 로직에 집중할 수 있습니다. 애플리케이션이 CRUD 작업을 기반으로 하고 사전 정의된 엔터티를 조작하는 경우, 수많은 개발자가 이전에 작성했지만 사용자의 인증 및 권한 부여 인프라를 다시 작성하는 것이 지겹거나 다음과 같은 훌륭한 웹 프레임워크의 모든 이점을 활용하려는 경우 Express, LoopBack으로 REST API를 구축하면 꿈을 이룰 수 있습니다. 한 조각의 케이크입니다!