From da78a9e329e272dedb2400b79a3bdeebff387d47 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:42:17 -0500 Subject: initial commit --- .../ko/learn/server-side/express_nodejs/index.html | 63 ++ .../express_nodejs/introduction/index.html | 488 +++++++++++++ .../server-side/express_nodejs/mongoose/index.html | 792 +++++++++++++++++++++ .../server-side/express_nodejs/routes/index.html | 639 +++++++++++++++++ .../index.html" | 403 +++++++++++ .../index.html" | 512 +++++++++++++ 6 files changed, 2897 insertions(+) create mode 100644 files/ko/learn/server-side/express_nodejs/index.html create mode 100644 files/ko/learn/server-side/express_nodejs/introduction/index.html create mode 100644 files/ko/learn/server-side/express_nodejs/mongoose/index.html create mode 100644 files/ko/learn/server-side/express_nodejs/routes/index.html create mode 100644 "files/ko/learn/server-side/express_nodejs/\352\260\234\353\260\234_\355\231\230\352\262\275/index.html" create mode 100644 "files/ko/learn/server-side/express_nodejs/\354\212\244\354\274\210\353\240\210\355\206\244_\354\233\271\354\202\254\354\235\264\355\212\270/index.html" (limited to 'files/ko/learn/server-side/express_nodejs') diff --git a/files/ko/learn/server-side/express_nodejs/index.html b/files/ko/learn/server-side/express_nodejs/index.html new file mode 100644 index 0000000000..453d7490f0 --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/index.html @@ -0,0 +1,63 @@ +--- +title: Express 웹 프레임워크 (Node.js/JavaScript의 활용) +slug: Learn/Server-side/Express_Nodejs +tags: + - Express + - node.js + - 서버 + - 시작 + - 웹프레임워크 + - 자바스크립트 + - 초보개발자 +translation_of: Learn/Server-side/Express_Nodejs +--- +
{{LearnSidebar}}
+ +

Express는 JavaScript로 작성되고 Node.js 런타임 환경에서 구동되는 인기 있는 웹 프레임워크입니다. 이 장에서는 Express 프레임워크의 몇 가지 장점과 개발환경 설치 방법, 웹 개발과 배포작업의 방법을 다룹니다.

+ +

알아야할 것들

+ +

이 장의 내용은 Server-side 웹 프로그래밍과 웹 프레임워크에 대한 이해가 필요합니다. 잘 모르겠다면 Server-side website programming first steps 을 먼저 확인해보세요. 일반적인 프로그래밍 컨셉과 JavaScript 의 지식이 요구되지만, 핵심까지 세세하게 알 필요는 없습니다.

+ +
+

Note: 여기서는 클라이언트 측에서의 자바스크립에 관한 많은 유용한 자료들을 이용할 수 있다.  JavaScriptJavaScript Guide, JavaScript BasicsJavaScript (한 번 배워보자). 자바스크립트의 핵심과 컨셉은 Node.js를 이용한 서버측 개발과 같으므로, 여기의 자료들을 이용하는 게 좋을 것이다. Node.js 는HTTP서버를 구축하고 파일 시스템에 접근하는 등의 브라우저가 필요없는 환경에서에서 유용한 기능을 제공하는 additional APIs를 제공하지만, 브라우저나 DOM에서 작동되는 자바스크립트 API는 지원하지 않는다.

+ +

다음 목차에서는 Node.js와 Express 그리고 인터넷과 책에서의 방대한 좋은 자료들에 있는 정보들을 알려준다. 이들은 How do I get started with Node.js (StackOverflow) 나 What are the best resources for learning Node.js? (Quora)에 참고해보자

+
+ +

목차

+ +
+
Express/Node introduction
+
처음으로 Express에 배우는 이 곳에서는 "Node가 뭐지?", "Express는 뭐지?"의 물음에 답하고, Express 웹 프레임워크의 전반적인 사항에 대해 알아볼 것이다. 주된 내용의 뼈대를 완성하고, Express 어플리케이션을 하나하나씩 배워볼 것이다. (하지만, 이 곳에서는 아직 어디서 테스팅이 이루어질 지 개발 환경등에서는 다루지 않을 것이다.).
+
Setting up a Node (Express) development environment
+
이제 Express가 어디에 이용되는지 알아볼 것이다. Windows, Linux(Ubuntu), Mac OS X에서 Node/Express의 개발환경을 구축하기 위한 방법도 살펴볼 것이다. 운영체제에 관계없이, 여기서는 Express 개발을 시작하기위해서 어떤 것이 필요한지도 알려준다.
+
Express Tutorial: The Local Library website
+
실질적인 튜토리얼에 해당하는 이번 수업에서는 어떤 것을 배우고 차후 수업에 필요한 "로컬 라이브러리"에서의 웹사이트의 전반적인 개요도 알아본다.
+
Express Tutorial Part 2: Creating a skeleton website
+
여기서는 웹사이트의 뼈대를 구성해 나갈 것이다. 웹사이트의 뼈대란 사이트의 사이트맵, 템플릿 및 데이터베이스등을 말하므로 이를 만들어볼 것이다.
+
Express Tutorial Part 3: Using a Database (with Mongoose)
+
여기서는 간단하게나마 Node/Express에 필요한 데이터베이스의 개요에 대해 소개할 것이다. 그리고 로컬의 웹사이트의 DB에 접근하기 위해 Mongoose를 사용하는 법도 알아본다. DB에서의 스키마와 모델이 어떻게 정의되는지, 필드의 타입과 기본적인 유효성에 대해서도 알아본다. 또한, 짧게나마 모델 데이터를 접근하는 주된 방법도 알아본다.
+
Express Tutorial Part 4: Routes and controllers
+
이 수업에서는 LocalLibray 웹사이트에 사용하기 위해 "더미" 핸들러 함수를 통한 라우터(URL 핸들링 코드)에 대해 배운다. 여러분의 라우팅 핸들링 코드를 사용할 수 있는 모듈 구조를 가지고 있으며, 다음 장에서 실제로 핸들러 기능을 확장할 수 있게 된다. 또한, Express에서 사용가능한 모듈 형식의 라우팅에 대해 쉽게 이해할 수 있을 것이다.
+
Express Tutorial Part 5: Displaying library data
+
자, 이제 웹사이트에 책이나 데이터들을 표시할 페이지를 추가할 수 있다. 페이지에는 사이트에 관련된 자세한 부분과 리스트 및 모델 타입들이 얼마나 많이 기록되는지에 관한 홈 페이지가 포함되어 있다. 따라서 우리들은 데이터베이스에서 기록을 얻고 템플릿을 사용하는 데 실질적인 경험을 가질 수 있다.
+
Express Tutorial Part 6: Working with forms
+
이 수업에서는 Pug를 사용해서 어떻게 Express에서 HTML Forms 이 사용되는지 보여주고, 특히 데이터베이스에서 폼을 작성하고 업데이트하고 지우기 위해 사용하는 방법에 대해 배울 것이다.
+
Express Tutorial Part 7: Deploying to production
+
이제 꽤 훌륭한 로컬라이브러리 웹사이트 만들 수 있으며 , 웹 서버에 업로드 함으로서 여러 사람들이 인터넷을 통해 접근할 수 있게 만들 수 있다. 이 수업은 전반적으로 웹 사이트를 배포하기 위해 호스트와 연결하는 등을 배우고, 실제 서비스를 하기위해 준비해야할 것들을 알려 준다.
+
+ +

튜토리얼 추가하기

+ +

자습서의 끝입니다. (지금은 말이죠). 만약 이 자습서의 내용을 보충하고 싶으시다면 아래와 같은 주제를 해 주시면 좋을 것 같네요:

+ + + +

그리고 평가 작업도 있으면 정말 좋을 것 같아요!

diff --git a/files/ko/learn/server-side/express_nodejs/introduction/index.html b/files/ko/learn/server-side/express_nodejs/introduction/index.html new file mode 100644 index 0000000000..caa4eb8eaa --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/introduction/index.html @@ -0,0 +1,488 @@ +--- +title: Express/Node 소개 +slug: Learn/Server-side/Express_Nodejs/Introduction +translation_of: Learn/Server-side/Express_Nodejs/Introduction +--- +
{{LearnSidebar}}
+ +
{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}
+ +

첫번째 Express 수업에서는 Node, Express를 알아보고, Express 웹 프레임워크 제작의 전반에 대해 배우게 됩니다.
+ 우선 주요 특징들에 대한 틀을 정리한 후 Express 어플리케이션을 구성하는 주요 구성요소들을 살펴볼 것입니다. (테스트할 개발환경은 아직이겠지만요)

+ + + + + + + + + + + + +
알아야 할 것들기본적인 컴퓨터의 이해. 서버 사이드 웹사이트 프로그래밍(server-side website programming), 그리고 특별히 웹사이트에서 클라이언트와 서버간의 상호작용(client-server interactions in websites)의 메커니즘에 대한 이해
목표Express에 익숙해지고, Node와 어떻게 함께 사용되는지, 기능은 어떠한지, 그리고 Express 어플리케이션의 주요한 구성요소들에 대해 배운다.
+ +

Express와 Node란?

+ +

Node (또는 더 공식적으로는 Node.js) 는 오픈소스, 크로스 플랫폼이며, 개발자가 모든 종류의 서버 사이드 도구들과 어플리케이션을 JavaScript로 만들수 있도록 해주는 런타임 환경이다.런타임은 브라우져 영역 밖에서도 사용할수 있도록 의도했다.(예를들면 서버 OS 또는 컴퓨터에서 직접적으로 실행되는). 이와 같이,  이 환경에서 특정 브라우져에서의 자바스트립트 API들을 제외시키고 ,  HTTP 와 파일 시스템 라이브러리들을 포함하여 더 많은 전형적인 OS API들을 추가했다.

+ +

웹 서버 관점에서 노드는 많은 장점들을 가진다:

+ + + +

Hello Node.js

+ +

아래 코드처럼 Node에 HTTP 모듈을 사용하여 모든 요청에 응답이 가능한 간단한 웹 서버를 쉽게 생성할 수 있습니다.

+ +

이렇게하면 웹 서버가 만들어지고 URL http://127.0.0.1:8000/ 에 있는 모든 종류의 HTTP 요청에 수신하게 됩니다. 요청이 하나 들어왔을 때, "Hello World" 텍스트 응답을 보내도록 하겠습니다.

+ +
    +
  1. 터미널을 연다. (윈도우에서는, 커맨드라인 유틸리티)
    + ※ 윈도우 키 + R => 'CMD'
  2. +
  3. 프로그램을 저장할 폴더를 생성하고(여기서는 test-node), 아래 명령을 입력하여 해당 폴더로 이동한다.
  4. +
+ +
cd test-node
+ +
    +
  1. 즐겨쓰는 텍스트에디터를 열어 아래 코드를 입력한 후, 파일명 hello.js 로 저장한다.
  2. +
+ +
//Load HTTP module
+var http = require("http");
+
+//Create HTTP server and listen on port 8000 for requests
+http.createServer(function (request, response) {
+
+   // Set the response HTTP header with HTTP status and Content type
+   response.writeHead(200, {'Content-Type': 'text/plain'});
+
+   // Send the response body "Hello World"
+   response.end('Hello World\n');
+}).listen(8000);
+
+// Print URL for accessing server
+console.log('Server running at http://127.0.0.1:8000/')
+ +

4. 터미널로 돌아가 아래 명령을 입력한다.

+ +
node hello.js
+ +

이제, 웹브라우저를 열어 다음 주소로 이동한다. http://localhost:8000 곧바로 좌상단에 "Hello World" 문구가 있고, 나머지 영역은 비어있는 웹페이지를 볼 수 있다.

+ +

Node 자체가 다른 일반적인 웹 개발 기능을 지원하지 않습니다. 만약 다른 HTTP 패턴 (예 : GET, POST, DELETE 등)에 대한 특정 처리를 추가하려면 서로 다른 URL 경로("routes")를 사용하여 요청을 개별적으로 처리, 정적 파일을 제공, 템플릿을 사용하여 동적으로 응답을 생성할 수 있으며, 코드를 직접 작성할 필요가가 생기게 됩니다. 또는 기본적인 것들을 직접 구현하는 작업을 피하고 웹 프레임 워크를 사용할 수 있습니다! 

+ +

Express 는 가장 인기있는 Node 웹 프레임 워크 이며, 다른 많은 인기있는 Node web frameworks의 기본 라이브러리 입니다. Express는 다음과 같은 메커니즘을 제공합니다:

+ + + +

Express 자체는 꽤나 최소한의 기능만 탑재하지만 개발자들이 거의 모든 웹 개발의 문제를 다루는 호환성있는 미들웨어 패키지를 만들어왔습니다. 쿠키, 세션, 사용자 로그인, URL 파라미터, POST 데이터, 보안 헤더와 그외 많은 것들에 대한 라이브러리들이 있습니다. 여러분은 Express Middleware에서 Express 팀이 유지보수하는 미들웨어 패키지 리스트를 확인할 수 있습니다. (유명한 서드파티 패키지들을 포함).

+ +
+

Note: This flexibility is a double edged sword. There are middleware packages to address almost any problem or requirement, but working out the right packages to use can sometimes be a challenge. There is also no "right way" to structure an application, and many examples you might find on the Internet are not optimal, or only show a small part of what you need to do in order to develop a web application.

+
+ +

유래

+ +

노드(Node)는 2009년 리눅스 한정으로 배포 되었다. NPM은 2010년에 배포되었고, 네이티브 윈도우즈(Windows)는 2012년부터 지원하기 시작하였다. 현재 배포중인 최신 LTS 버전은 Node v8.9.3이 있고, 가장 최신 버전은 Node 9 이다. 이것은 유구한 역사를 짧게 적어본 것으로 더 알고 싶다면 위키페디아를 참조하면 된다.

+ +

Express는 2010년 11월 처음 배포되었고 현재는 4.16 버전이 되었다. 현재 배포 버전과의 변경사항을 알고 싶다면 changelog 를 확인하면 된다. 그리고 더 자세한 역사와 릴리즈 노트는 GitHub 를 참조하면 된다.

+ +

어떻게 Node/Express가 유명해졌을까?

+ +

유명한 웹 프레임워크 쓴다는 것은 아주 중요합니다. 바로 해당 기술에 대한 지속가능성, 문서화, 추가 라이브러리, 그리고 기술 지원 자원에 대한 지표가 되기 때문입니다. 

+ +

There isn't any readily-available and definitive measurement of the popularity of server-side frameworks (although sites like Hot Frameworks attempt to assess popularity using mechanisms like counting the number of GitHub projects and StackOverflow questions for each platform). A better question is whether Node and Express are "popular enough" to avoid the problems of unpopular platforms. Are they continuing to evolve? Can you get help if you need it? Is there an opportunity for you to get paid work if you learn Express?

+ +

Based on the number of high profile companies that use Express, the number of people contributing to the codebase, and the number of people providing both free and paid for support, then yes, Express is a popular framework!

+ +

Express는 개발이 자유로울까?

+ +

Web frameworks often refer to themselves as "opinionated" or "unopinionated".

+ +

Opinionated frameworks are those with opinions about the "right way" to handle any particular task. They often support rapid development in a particular domain (solving problems of a particular type) because the right way to do anything is usually well-understood and well-documented. However they can be less flexible at solving problems outside their main domain, and tend to offer fewer choices for what components and approaches they can use.

+ +

Unopinionated frameworks, by contrast, have far fewer restrictions on the best way to glue components together to achieve a goal, or even what components should be used. They make it easier for developers to use the most suitable tools to complete a particular task, albeit at the cost that you need to find those components yourself.
+
+ Express is unopinionated. You can insert almost any compatible middleware you like into the request handling chain, in almost any order you like. You can structure the app in one file or multiple files, and using any directory structure. You may sometimes feel that you have too many choices!

+ +

Express의 코드는 어떻게 생겼을까?

+ +

In a traditional data-driven website, a web application waits for HTTP requests from the web browser (or other client). When a request is received the application works out what action is needed based on the URL pattern and possibly associated information contained in POST data or GET data. Depending on what is required it may then read or write information from a database or perform other tasks required to satisify the request. The application will then return a response to the web browser, often dynamically creating an HTML page for the browser to display by inserting the retrieved data into placeholders in an HTML template.

+ +

Express provides methods to specify what function is called for a particular HTTP verb (GET, POST, SET, etc.) and URL pattern ("Route"), and methods to specify what template ("view") engine is used, where template files are located, and what template to use to render a response. You can use Express middleware to add support for cookies, sessions, and users, getting POST/GET parameters, etc. You can use any database mechanism supported by Node (Express does not define any database-related behaviour).

+ +

The following sections explain some of the common things you'll see when working with Express and Node code.

+ +

Helloworld Express

+ +

First lets consider the standard Express Hello World example (we discuss each part of this below, and in the following sections).

+ +
+

Tip: If you have Node and Express already installed (or if you install them as shown in the next article), you can save this code in a file called app.js and run it in a command prompt by calling node app.js.

+
+ +
var express = require('express');
+var app = express();
+
+app.get('/', function (req, res) {
+  res.send('Hello World!');
+});
+
+app.listen(3000, function () {
+  console.log('Example app listening on port 3000!');
+});
+
+ +

The first two lines require() (import) the express module and create an Express application. This object, which is traditionally named app, has methods for routing HTTP requests, configuring middleware, rendering HTML views, registering a template engine, and modifying application settings that control how the application behaves (e.g. the environment mode, whether route definitions are case sensitive, etc.)

+ +

The middle part of the code (the three lines starting with app.get) shows a route definition. The app.get() method specifies a callback function that will be invoked whenever there is an HTTP GET request with a path ('/') relative to the site root. The callback function takes a request and a response object as arguments, and simply calls send() on the response to return the string "Hello World!"

+ +

The final block starts up the server on port '3000' and prints a log comment to the console. With the server running, you could go to localhost:3000 in your browser to see the example response returned.

+ +

모듈의 생성과 불러옴(Importing and creating modules)

+ +

A module is a JavaScript library/file that you can import into other code using Node's require() function. Express itself is a module, as are the middleware and database libraries that we use in our Express applications.

+ +

The code below shows how we import a module by name, using the Express framework as an example. First we invoke the require() function, specifying the name of the module as a string ('express'), and calling the returned object to create an Express application. We can then access the properties and functions of the application object.

+ +
var express = require('express');
+var app = express();
+
+ +

You can also create your own modules that can be imported in the same way.

+ +
+

Tip: You will want to create your own modules, because this allows you to organise your code into managable parts — a monolithic single-file application is hard to understand and maintain. Using modules also helps you manage your namespace, because only the variables you explicitly export are imported when you use a module.

+
+ +

To make objects available outside of a module you just need to assign them to the exports object. For example, the square.js module below is a file that exports area() and perimeter() methods:

+ +
exports.area = function (width) { return width * width; };
+exports.perimeter = function (width) { return 4 * width; };
+
+ +

We can import this module using require(), and then call the exported method(s) as shown:

+ +
var square = require('./square'); // Here we require() the name of the file without the (optional) .js file extension
+console.log('The area of a square with a width of 4 is ' + square.area(4));
+ +
+

Note: You can also specify an absolute path to the module (or a name, as we did initially).

+
+ +

If you want to export a complete object in one assignment instead of building it one property at a time, assign it to module.exports as shown below (you can also do this to make the root of the exports object a constructor or other function):

+ +
module.exports = {
+  area: function(width) {
+    return width * width;
+  },
+
+  perimeter: function(width) {
+    return 4 * width;
+  }
+};
+
+ +

For a lot more information about modules see Modules (Node API docs).

+ +

비동기식 API의 사용

+ +

JavaScript 코드는 완료까지 시간이 다소 소요될 수 있는 작업에 대해 동기보다 비동기 API를 자주 사용합니다. 동기 API는 다음 작업이 시작하기 전에 각 작업이 완료되어야만 합니다. 예를 들어, 다음의 로그함수들은 동기식이며 텍스트를 순서대로 콘솔에 나타낼 것입니다.(First, Second)

+ +
console.log('First');
+console.log('Second');
+ +

반면 비동기 API는 API가 작업을 시작하고, 즉시 반환(작업이 완료되기 전에)합니다. 작업이 완료되면 API는 추가적인 작업 수행을 위한 일부 매커니즘을 사용합니다. 예를 들어 아래의 코드는  "Second, First"를 출력합니다. 그   이유는 setTimeout() 메서드가 먼저 호출되고 즉시 반환되더라도, 작업이 몇 초 동안 완료되지 않기 때문입니다.

+ +
setTimeout(function() {
+   console.log('First');
+   }, 3000);
+console.log('Second');
+
+ +

Node는 싱글 스레드 이벤트 기반 환경이기 때문에 non-blocking 비동기 API는 브라우저보다 Node에서 훨씬 더 중요합니다.

+ +

'싱글 스레드'는 서버에 모든 요청이 별도의 프로세스로 생성되지 않고 동일한 스레드에서 실행되는 것을 의미합니다. 이 모델은 속도와 서버 리소스 측면에서 아주 효율적이지만, 만약 특정 함수가 완료되는데에 오랜 시간이 걸리는 동기 메서드를 호출하는 함수가 있다면 현재 요청 뿐만 아니라 웹 어플리케이션에서 다른 요청이 처리되는 것도 차단합니다.

+ +

비동기 API가 완료되었음을 어플리케이션에 알리는 방법은 여러가지가 있습니다. 가장 일반적인 방법은 비동기 API를 호출시 작업이 완료되면 다시 호출되는 콜백함수를 이용하는 것이며, 위의 예제에서 사용된 방식입니다.

+ +
+

Tip: 순서대로 수행해야하는 종속적인 비동기 작업들이 있을 경우, 콜백을 사용하는 것은 꽤 복잡할 수 있습니다. 중첩된 여러 단계의 콜백이 생성되기 때문입니다. 이 문제는 흔히 'callback hell'이라고 일컬어집니다. 이 문제는 good coding practices(http://callbackhell.com/ 참고), async와 같은 모듈의 사용, Promises와 같은 ES6 기능을 사용함으로써 개선될 수 있습니다.

+
+ +
+

Note: Node와 Express의 일반적인 규칙은 error-first callbacks을 사용하는 것입니다. 이 규칙에서 콜백 함수의 첫번 째 값은 에러값이고, 다음 인자에는 성공 데이터가 포함됩니다. 이 방법에 대한 좋은 설명은 이 블로그에서 확인할 수 있습니다.:: The Node.js Way - Understanding Error-First Callbacks (fredkschott.com).

+
+ +

라우트 핸들러의 사용

+ +

In our Hello World Express example see above we defined a (callback) route handler function for HTTP GET requests to the site root ('/').

+ +
app.get('/', function (req, res) {
+  res.send('Hello World!');
+});
+
+ +

The callback function takes a request and a response object as arguments. In this case the method simply calls send() on the response to return the string "Hello World!" There are a number of other response methods for ending the request/response cycle, for example you could call res.json() to send a JSON response or res.sendFile() to send a file.

+ +
+

JavaScript tip: You can use any argument names you like in the callback functions; when the callback is invoked the first argument will always be the request and the second will always be the response. It makes sense to name them such that you can identify the object you're working with in the body of the callback.

+
+ +

The Express application object also provides methods to define route handlers for all the other HTTP verbs, which are mostly used in exactly the same way: post(), put(), delete(), options(), trace(), copy(), lock(), mkcol(), move(), purge(), propfind(), proppatch(), unlock(), report(), ​​​​​​ mkactivity(), checkout(), merge(), m-search(), notify(), subscribe(), unsubscribe(), patch(), search(), and connect().

+ +

There is a special routing method, app.all(), which will be called in response to any HTTP method. This is used for loading middleware functions at a particular path for all request methods. The following example (from the Express documentation) shows a handler that will be executed for requests to /secret irrespective of the HTTP verb used (provided it is supported by the http module).

+ +
app.all('/secret', function (req, res, next) {
+  console.log('Accessing the secret section ...')
+  next() // pass control to the next handler
+})
+ +

Routes allow you to match particular patterns of characters in a URL, and extract some values from the URL and pass them as parameters to the route handler (as attributes of the request object passed as a parameter).

+ +

Often it is useful to group route handlers for a particular part of a site together and access them using a common route-prefix (e.g. a site with a Wiki might have all wiki-related routes in one file and have them accessed with a route prefix of /wiki/). In Express this is achieved by using the express.Router object. For example, we can create our wiki route in a module named wiki.js, and then export the Router object, as shown below:

+ +
// wiki.js - Wiki route module
+
+var express = require('express')
+var router = express.Router()
+
+// Home page route
+router.get('/', function (req, res) {
+  res.send('Wiki home page')
+})
+
+// About page route
+router.get('/about', function (req, res) {
+  res.send('About this wiki')
+})
+
+module.exports = router
+
+ +
+

Note: Adding routes to the Router object is just like adding routes to the app object (as shown previously).

+
+ +

To use the router in our main app file we would then require() the route module (wiki.js), then call use() on the Express application to add the Router to the middleware handling path. The two routes will then be accessible from /wiki/ and /wiki/about/.

+ +
var wiki = require('./wiki.js')
+// ...
+app.use('/wiki', wiki)
+ +

We'll show you a lot more about working with routes, and in particular about using the Router, later on in the linked section Routes and controllers .

+ +

미들웨어의 사용

+ +

미들웨어는 정적 파일 제공에서 오류 처리, HTTP 응답 압축에 이르기까지 Express 앱에서 광범위하게 사용됩니다. 라우트 함수는 HTTP 클라이언트에 일부 응답을 반환하여 HTTP 요청-응답주기를 종료하는 반면, 미들웨어 함수는 일반적으로 요청 또는 응답에 대해 일부 작업을 수행 한 다음 "스택"(이는 미들웨어 혹은 라우트 핸들러일 수 있습니다.)에서 다음 함수를 호출합니다.  미들웨어가 호출되는 순서는 앱 개발자에게 달려있습니다.

+ +
+

Note: 미들웨어는 모든 작업을 수행하고, 코드를 실행하고, 요청 및 응답 객체를 변경할 수 있으며, 요청-응답주기를 종료 할 수도 있습니다. 만약 주기가 종료되지 않으면, 다음 미들웨어 함수의 제어를 위해 next()를 호출해야합니다.( 혹은 요청이 중단된 상태로 유지될 것입니다.)

+
+ +

대부분의 앱은 쿠키, 세션, 사용자 인증, POST요청 및 JSON 데이터 접근 , logging 등과 같은 일반적인 웹 개발 작업을 단순화하기 위해서드파티 미들웨어를 사용합니다 . Express 팀에서 관리하는 미들웨어 패키지 목록을 이 곳에서 찾을 수 있습니다 ( 다른 인기있는 서드파티 패키지도 포함). 다른 Express 패키지는 NPM 패키지 관리자에서 사용할 수 있습니다.

+ +

서드파티 미들웨어를 사용하려면 먼저 NPM을 사용하여 앱에 설치해야합니다. 예를 들어 morgan HTTP 요청 logger 미들웨어 를 설치하려면 다음과 같이 진행합니다.

+ +
$ npm install morgan
+
+ +

그런 다음 Express application object에 use()를 호출해서 스택에 이 미들웨어를 추가합니다.

+ +
var express = require('express');
+var logger = require('morgan');
+var app = express();
+app.use(logger('dev'));
+...
+ +
+

Note: 미들웨어 및 라우팅 함수는 선언된 순서대로 호출됩니다. 일부 미들웨어의 경우 순서가 중요합니다 (예를 들어 세션 미들웨어가 쿠키 미들웨어에 의존하는 경우, 쿠키 핸들러를 먼저 추가해야합니다). 거의 항상 라우트를 설정하기 전에 미들웨어가 호출되거나,  미들웨어로 인해 추가된 기능에 라우트 핸들러가  접근할 수 없습니다.

+
+ +

당신은 자신만의 미들웨어 함수를 작성할 수 있으며, 그렇게 해야 할 가능성이 높습니다 (에러 처리 코드를 생성하는 경우에만 해당). 미들웨어 함수와 라우트 핸들러 콜백 의 유일한 차이점은 미들웨어 함수에 세 번째 인자로 미들웨어 함수가 요청 주기를 완료하지 않을 때 호출되는 next가 있다는 것입니다. (미들웨어 함수가 호출 될 때 여기에는 반드시 호출되는 next 함수가 포함됩니다.).

+ +

당신이 모든 응답 혹은  특정 HTTP 동사(GETPOST 등)에 미들웨어를 적용할지 여부에 따라app.use()또는 app.add()와 함께 프로세싱 체인에 미들웨어 기능을 추가 할 수 있습니다. 두 경우 모두 라우트를 동일하게 지정하지만 app.use () 호출시 라우트는 선택 사항 입니다.

+ +

아래의  예제는 두 가지 방법을 사용하고, 경로를 사용하거나 사용하지 않고 미들웨어 기능을 추가하는 방법을 보여줍니다.

+ +
var express = require('express')
+var app = express()
+
+// An example middleware function
+var a_middleware_function = function(req, res, next) {
+  //... perform some operations
+  next(); //Call next() so Express will call the next middleware function in the chain.
+}
+
+// Function added with use() for all routes and verbs
+app.use(a_middleware_function)
+
+//Function added with use() for a specific route
+app.use('/someroute', a_middleware_function)
+
+// A middleware function added for a specific HTTP verb and route
+app.get('/', a_middleware_function )
+
+app.listen(3000)
+ +
+

JavaScript Tip: 위에서 우리는 미들웨어 함수를 별도로 선언 한 다음 그것을 콜백으로 설정합니다. 이전 라우트 핸들러 함수에서는 우리는 콜백 함수가 사용될 때 선언했습니다. JavaScript에서는 두 방법 모두 유효합니다.

+
+ +

Express 공식 문서에는 Express 미들웨어 사용 및 작성 에 대한 훨씬 더 우수한 자료들이 있습니다.

+ +

저장된 파일을 서버화하기

+ +

You can use the express.static middleware to serve static files, including your images, CSS and JavaScript (static() is the only middleware function that is actually part of Express). For example, you would use the line below to serve images, CSS files, and JavaScript files from a directory named 'public' at the same level as where you call node:

+ +
app.use(express.static('public'))
+
+ +

Any files in the public directory are served by adding their filename (relative to the base "public" directory) to the base URL. So for example:

+ +
http://localhost:3000/images/dog.jpg
+http://localhost:3000/css/style.css
+http://localhost:3000/js/app.js
+http://localhost:3000/about.html
+
+ +

You can call static() multiple times to serve multiple directories. If a file cannot be found by one middleware function then it will simply be passed on to the subsequent middleware (the order that middleware is called is based on your declaration order).

+ +
app.use(express.static('public'))
+app.use(express.static('media'))
+
+ +

You can also create a virtual prefix for your static URLs, rather than having the files added to the base URL. For example, here we specify a mount path so that the files are loaded with the prefix "/media":

+ +
app.use('/media', express.static('public'))
+
+ +

Now, you can load the files that are in the public directory from the /media path prefix.

+ +
http://localhost:3000/media/images/dog.jpg
+http://localhost:3000/media/video/cat.mp4
+http://localhost:3000/media/cry.mp3
+
+ +

For more information, see Serving static files in Express.

+ +

핸들링 에러

+ +

Errors are handled by one or more special middleware functions that have four arguments, instead of the usual three: (err, req, res, next). For example:

+ +
app.use(function (err, req, res, next) {
+  console.error(err.stack)
+  res.status(500).send('Something broke!')
+})
+
+ +

These can return any content required, but must be called after all other app.use() and routes calls so that they are the last middleware in the request handling process!

+ +

Express comes with a built-in error handler, which takes care of any remaining errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack. If you pass an error to next() and you do not handle it in an error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace.

+ +
+

Note: The stack trace is not included in the production environment. To run it in production mode you need to set the the environment variable NODE_ENV to 'production'.

+
+ +
+

Note: HTTP404 and other "error" status codes are not treated as errors. If you want to handle these, you can add a middleware function to do so. For more information see the FAQ.

+
+ +

For more information see Error handling (Express docs).

+ +

데이터베이스의 사용

+ +

Express apps can use any database mechanism supported by Node (Express itself doesn't define any specific additional behaviour/requirements for database management). There are many options, including PostgreSQL, MySQL, Redis, SQLite, MongoDB, etc.

+ +

In order to use these you have to first install the database driver using NPM. For example, to install the driver for the popular NoSQL MongoDB you would use the command:

+ +
$ npm install mongodb
+
+ +

The database itself can be installed locally or on a cloud server. In your Express code you require the driver, connect to the database, and then perform create, read, update, and delete (CRUD) operations. The example below (from the Express documentation) shows how you can find "mammal" records using MongoDB.

+ +
var MongoClient = require('mongodb').MongoClient
+
+MongoClient.connect('mongodb://localhost:27017/animals', function (err, db) {
+  if (err) throw err
+
+  db.collection('mammals').find().toArray(function (err, result) {
+    if (err) throw err
+
+    console.log(result)
+  })
+})
+ +

Another popular approach is to access your database indirectly, via an Object Relational Mapper ("ORM"). In this approach you define your data as "objects" or "models" and the ORM maps these through to the underlying database format. This approach has the benefit that as a developer you can continue to think in terms of JavaScript objects rather than database semantics, and that there is an obvious place to perform validation and checking of incoming data. We'll talk more about databases in a later article.

+ +

For more information see Database integration (Express docs).

+ +

데이터 랜더링(시각화)

+ +

Template engines (referred to as "view engines" by Express) allow you to specify the structure of an output document in a template, using placeholders for data that will be filled in when a page is generated. Templates are often used to create HTML, but can also create other types of document. Express has support for a number of template engines, and there is a useful comparison of the more popular engines here: Comparing JavaScript Templating Engines: Jade, Mustache, Dust and More.

+ +

In your application settings code you set the template engine to use and the location where Express should look for templates using the 'views' and 'view engines' settings, as shown below (you will also have to install the package containing your template library too!)

+ +
var express = require('express');
+var app = express();
+
+// Set directory to contain the templates ('views')
+app.set('views', path.join(__dirname, 'views'));
+
+// Set view engine to use, in this case 'some_template_engine_name'
+app.set('view engine', 'some_template_engine_name');
+
+ +

The appearance of the template will depend on what engine you use. Assuming that you have a template file named "index.<template_extension>" that contains placeholders for data variables named 'title' and "message", you would call Response.render() in a route handler function to create and send the HTML response:

+ +
app.get('/', function (req, res) {
+  res.render('index', { title: 'About dogs', message: 'Dogs rock!' })
+})
+ +

For more information see Using template engines with Express (Express docs).

+ +

파일구조

+ +

Express makes no assumptions in terms of structure or what components you use. Routes, views, static files, and other application-specific logic can live in any number of files with any directory structure. While it is perfectly possible to have the whole Express application in one file, typically it makes sense to split your application into files based on function (e.g. account management, blogs, discussion boards) and architectural problem domain (e.g. model, view or controller if you happen to be using an MVC architecture).

+ +

In a later topic we'll use the Express Application Generator, which creates a modular app skeleton that we can easily extend for creating web applications.

+ + + +

요약

+ +

Congratulations, you've completed the first step in your Express/Node journey! You should now understand Express and Node's main benefits, and roughly what the main parts of an Express app might look like (routes, middleware, error handling, and template code). You should also understand that with Express being an unopinionated framework, the way you pull these parts together and the libraries that you use are largely up to you!

+ +

Of course Express is deliberately a very lightweight web application framework, so much of its benefit and potential comes from third party libraries and features. We'll look at those in more detail in the following articles. In our next article we're going to look at setting up a Node development environment, so that you can start seeing some Express code in action.

+ +

더보기

+ + + +
{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}
diff --git a/files/ko/learn/server-side/express_nodejs/mongoose/index.html b/files/ko/learn/server-side/express_nodejs/mongoose/index.html new file mode 100644 index 0000000000..07c0f1e422 --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/mongoose/index.html @@ -0,0 +1,792 @@ +--- +title: 'Express Tutorial Part 3: Using a Database (with Mongoose)' +slug: Learn/Server-side/Express_Nodejs/mongoose +translation_of: Learn/Server-side/Express_Nodejs/mongoose +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}
+ +

이번에는 데이터베이스를 간단히 소개하고, Node/Express 어플리케이션으로 데이터베이스를 어떻게 다루는 지 알아보겠습니다. 그리고 LocalLibrary 웹사이트를 위한 데이터베이스 접근을 제공하는 Mongoose를 어떻게 사용할 수 있는지 보여줄 것입니다. 오브젝트 스키마와 모델을 선언하는 방법, 주요 필드 타입, 기본 유효성 검사를 설명합니다. 또한 당신이 모델 데이터에 접근할 수 있는 주요한 몇가지 방법들을 소개할 것입니다.

+ + + + + + + + + + + + +
Prerequisites:Express Tutorial Part 2: Creating a skeleton website
Objective:To be able to design and create your own models using Mongoose.
+ +

개요

+ +

도서관 직원들은 책과 대여자의 정보를 저장하기 위해 Local Library 웹사이트를 사용할 것입니다. 그리고 도서관 회원들은 책을 빌리고, 검색하며, 어떤 책이 이용한지 알아내고, 책 대여를 예약하거나 책을 빌릴 것입니다. 정보를 효과적으로 저장하고 가져오기 위해서, 우리는 그 정보를 데이터베이스에 저장할 것입니다.

+ +

Express 앱은 다양한 데이터베이스를 사용할 수 있고, 당신에게 CRUD(Create, Read, Update and Delete)를 수행할 수 있는 여러 방법을 제공합니다. 이번 튜토리얼은 이용가능한 몇가지 선택지에 대한 간략한 개요를 제공하며, 더 나아가 우리가 선택한 몇가지 메커니즘에 대해선 자세히 알아볼 것입니다.

+ +

사용할 수 있는 데이터베이스는 무엇이 있나요?

+ +

Express 앱은 노드에서 지원하는 어떤 데이터베이스라도 사용가능합니다. (Express 자체는 데이터베이스 관리에 대한 특정한 추가 동작/요구사항을 정의하지 않습니다.) PostgreSQL, MySQL, Redis, SQLite, and MongoDB를 포함한 많은 인기있는 데이터베이스 옵션을 선택가능합니다.

+ +

데이터베이스를 고를때, 당신은 생산성/러닝커브, 성능, 쉬운 리플리케이션/백업, 비용, 커뮤니티 지원 등을 고려해야 합니다. 하나의 "최고"  데이터베이스를 정하지 못하는 동안, 우리의 Local Library 같이 작은 규모에서 중간규모의 사이트에 적합한 거의 모든 어떤 솔루션이라도 사용 가능해야 합니다.

+ +

옵션에 대한 더 많은 정보는 여기를 보십시오: 데이터베이스 인테그레이션 (Express 문서)

+ +

데이터베이스와 상호작용하는 최소의 방법은 무엇인가요?

+ +

데이터베이스와 상호작용하는 두가지 접근법이 있습니다: 

+ + + +

최상의 퍼포먼스는 SQL이나 데이터베이스에서 지원하는 쿼리 언어를 사용할때 얻을 수 있습니다. ODM은 오브젝트와 데이터베이스 포맷을 매핑하는 변환코드를 사용하기 때문에 종종 느리며, 가장 효율적인 데이터베이스 쿼리를 사용하지 않을 수 있습니다.

+ +

ORM을 사용하는 이점은 프로그래머가 데이터베이스의 의미보다 JavaScript 객체로 계속해서 생각할 수 있다는 것입니다.  - 이는 다른 데이터베이스(같거나 다른 웹사이트 어느 쪽에서든)들에서 작업해야 하는 경우 특히 그렇습니다. 또한 데이터의 유효성 및 확인을 확실히 할 수 있습니다.

+ +
+

팁:  ODM/ORM을 사용하면 개발 및 유지 보수 비용이 절감됩니다. 네이티브 쿼리 언어에 친숙하거나 퍼포먼스가 중요한 것이 아니라면, ODM 사용을 적극 고려해야 합니다.

+
+ +

NPM 패키지 매니저 사이트에는 사용가능한 많은 ODM/ORM 솔루션이 있습니다.(odm 과 orm 태그 집합을 확인하십시오.)

+ +

이 글 작성 시점에 인기있었던 솔루션은 다음과 같습니다:

+ + + +

일반적으로 솔루션을 선택할 때, 당신은 제공되는 기능과 "커뮤니티 활동" (다운로드, 공헌도, 버그 리포트, 문서 퀄리티 등) 모두를 고려해야 합니다. 이에 대한 글을 작성하고 있는 시점에, 몽구스는 가장 유명한 ORM이며, 당신이 MongoDB를 사용한다면 몽구스는 합리적인 선택입니다.

+ +

Using Mongoose and MongoDb for the LocalLibrary

+ +

For the Local Library example (and the rest of this topic) we're going to use the Mongoose ODM to access our library data. Mongoose acts as a front end to MongoDB, an open source NoSQL database that uses a document-oriented data model. A “collection” of “documents”, in a MongoDB database, is analogous to a “table” of “rows” in a relational database.

+ +

This ODM and database combination is extremely popular in the Node community, partially because the document storage and query system looks very much like JSON, and is hence familiar to JavaScript developers.

+ +
+

Tip: You don't need to know MongoDB in order to use Mongoose, although parts of the Mongoose documentation are easier to use and understand if you are already familiar with MongoDB.

+
+ +

The rest of this tutorial shows how to define and access the Mongoose schema and models for the LocalLibrary website example.

+ +

Designing the LocalLibrary models

+ +

Before you jump in and start coding the models, it's worth taking a few minutes to think about what data we need to store and the relationships between the different objects.

+ +

We know that we need to store information about books (title, summary, author, genre, ISBN) and that we might have multiple copies available (with globally unique ids, availability statuses, etc.). We might need to store more information about the author than just their name, and there might be multiple authors with the same or similar names. We want to be able to sort information based on book title, author, genre, and category.

+ +

When designing your models it makes sense to have separate models for every "object" (group of related information). In this case the obvious objects are books, book instances, and authors.

+ +

You might also want to use models to represent selection-list options (e.g. like a drop down list of choices), rather than hard coding the choices into the website itself — this is recommended when all the options aren't known up front or may change. The obvious candidate for a model of this type is the book genre (e.g. Science Fiction, French Poetry, etc.)

+ +

Once we've decided on our models and fields, we need to think about the relationships between them.

+ +

With that in mind, the UML association diagram below shows the models we'll define in this case (as boxes). As discussed above, we've created models for book (the generic details of the book), book instance (status of specific physical copies of the book available in the system), and author. We have also decided to have a model for genre, so that values can be created dynamically. We've decided not to have a model for the BookInstance:status — we will hard code the acceptable values because we don't expect these to change. Within each of the boxes you can see the model name, the field names and types, and also the methods and their return types.

+ +

The diagram also shows the relationships between the models, including their multiplicities. The multiplicities are the numbers on the diagram showing the numbers (maximum and minimum) of each model that may be present in the relationship. For example, the connecting line between the boxes shows that Book and a Genre are related. The numbers close to the Book model show that a book must have zero or more Genre (as many as you like), while the numbers on the other end of the line next to the Genre show that it can have zero or more associated books.

+ +
+

Note: As discussed in our Mongoose primer below it is often better to have the field that defines the relationship between the documents/models in just one model (you can still find the reverse relationship by searching for the associated _id in the other model). Below we have chosen to define the relationship between Book/Genre and Book/Author in the Book schema, and the relationship between the Book/BookInstance in the BookInstance Schema. This choice was somewhat arbitrary — we could equally well have had the field in the other schema.

+
+ +

Mongoose Library Model  with correct cardinality

+ +
+

Note: The next section provides a basic primer explaining how models are defined and used. As you read it, consider how we will construct each of the models in the diagram above.

+
+ +

Mongoose primer

+ +

This section provides an overview of how to connect Mongoose to a MongoDB database, how to define a schema and a model, and how to make basic queries. 

+ +
+

Note: This primer is "heavily influenced" by the Mongoose quick start on npm and the official documentation.

+
+ +

Installing Mongoose and MongoDB

+ +

Mongoose is installed in your project (package.json) like any other dependency — using NPM. To install it, use the following command inside your project folder:

+ +
npm install mongoose
+
+ +

Installing Mongoose adds all its dependencies, including the MongoDB database driver, but it does not install MongoDB itself. If you want to install a MongoDB server then you can download installers from here for various operating systems and install it locally. You can also use cloud-based MongoDB instances.

+ +
+

Note: For this tutorial we'll be using the mLab cloud-based database as a service sandbox tier to provide the database. This is suitable for development, and makes sense for the tutorial because it makes "installation" operating system independent (database-as-a-service is also one approach you might well use for your production database).

+
+ +

Connecting to MongoDB

+ +

Mongoose requires a connection to a MongoDB database. You can require() and connect to a locally hosted database with mongoose.connect(), as shown below.

+ +
//Import the mongoose module
+var mongoose = require('mongoose');
+
+//Set up default mongoose connection
+var mongoDB = 'mongodb://127.0.0.1/my_database';
+mongoose.connect(mongoDB);
+// Get Mongoose to use the global promise library
+mongoose.Promise = global.Promise;
+//Get the default connection
+var db = mongoose.connection;
+
+//Bind connection to error event (to get notification of connection errors)
+db.on('error', console.error.bind(console, 'MongoDB connection error:'));
+ +

You can get the default Connection object with mongoose.connection. Once connected, the open event is fired on the Connection instance.

+ +
+

Tip: If you need to create additional connections you can use mongoose.createConnection(). This takes the same form of database URI (with host, database, port, options etc.) as connect() and returns a Connection object).

+
+ +

Defining and creating models

+ +

Models are defined using the Schema interface. The Schema allows you to define the fields stored in each document along with their validation requirements and default values. In addition, you can define static and instance helper methods to make it easier to work with your data types, and also virtual properties that you can use like any other field, but which aren't actually stored in the database (we'll discuss a bit further below).

+ +

Schemas are then "compiled" into models using the mongoose.model() method. Once you have a model you can use it to find, create, update, and delete objects of the given type.

+ +
+

Note: Each model maps to a collection of documents in the MongoDB database. The documents will contain the fields/schema types defined in the model Schema.

+
+ +

Defining schemas

+ +

The code fragment below shows how you might define a simple schema. First you require() mongoose, then use the Schema constructor to create a new schema instance, defining the various fields inside it in the constructor's object parameter.

+ +
//Require Mongoose
+var mongoose = require('mongoose');
+
+//Define a schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+    a_string: String,
+    a_date: Date
+});
+
+ +

In the case above we just have two fields, a string and a date. In the next sections we will show some of the other field types, validation, and other methods.

+ +

Creating a model

+ +

Models are created from schemas using the mongoose.model() method:

+ +
// Define schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+    a_string: String,
+    a_date: Date
+});
+
+// Compile model from schema
+var SomeModel = mongoose.model('SomeModel', SomeModelSchema );
+ +

The first argument is the singular name of the collection that will be created for your model (Mongoose will create the database collection for the above model SomeModel above), and the second argument is the schema you want to use in creating the model.

+ +
+

Note: Once you've defined your model classes you can use them to create, update, or delete records, and to run queries to get all records or particular subsets of records. We'll show you how to do this in the Using models section, and when we create our views.

+
+ +

스키마 타입 (필드)

+ +

한 스키마는 임의의 숫자의 필드들을 가질 수 있습니다.(각각의 필드는 MongoDB에 저장된 문서의 필드를 대표합니다.) 아래의 예제 스키마는 일반적인 필드 타입들을 보여주고 있으며 그들이 어떻게 선언되는지 나타냅니다.

+ +
var schema = new Schema(
+{
+  name: String,
+  binary: Buffer,
+  living: Boolean,
+  updated: { type: Date, default: Date.now },
+  age: { type: Number, min: 18, max: 65, required: true },
+  mixed: Schema.Types.Mixed,
+  _someId: Schema.Types.ObjectId,
+  array: [],
+  ofString: [String], // You can also have an array of each of the other types too.
+  nested: { stuff: { type: String, lowercase: true, trim: true } }
+})
+ +

Most of the SchemaTypes (the descriptors after “type:” or after field names) are self explanatory. The exceptions are:

+ + + +

The code also shows both ways of declaring a field:

+ + + +

For more information about options see SchemaTypes (Mongoose docs).

+ +

Validation

+ +

Mongoose provides built-in and custom validators, and synchronous and asynchronous validators. It allows you to specify both the acceptable range or values and the error message for validation failure in all cases.

+ +

The built-in validators include:

+ + + +

The example below (slightly modified from the Mongoose documents) shows how you can specify some of the validator types and error messages:

+ +

+    var breakfastSchema = new Schema({
+      eggs: {
+        type: Number,
+        min: [6, 'Too few eggs'],
+        max: 12
+        required: [true, 'Why no eggs?']
+      },
+      drink: {
+        type: String,
+        enum: ['Coffee', 'Tea', 'Water',]
+      }
+    });
+
+ +

For complete information on field validation see Validation (Mongoose docs).

+ +

Virtual properties

+ +

Virtual properties are document properties that you can get and set but that do not get persisted to MongoDB. The getters are useful for formatting or combining fields, while setters are useful for de-composing a single value into multiple values for storage. The example in the documentation constructs (and deconstructs) a full name virtual property from a first and last name field, which is easier and cleaner than constructing a full name every time one is used in a template.

+ +
+

Note: We will use a virtual property in the library to define a unique URL for each model record using a path and the record's _id value.

+
+ +

For more information see Virtuals (Mongoose documentation).

+ +

Methods and query helpers

+ +

A schema can also have instance methods, static methods, and query helpers. The instance and static methods are similar, but with the obvious difference that an instance method is associated with a particular record and has access to the current object. Query helpers allow you to extend mongoose's chainable query builder API (for example, allowing you to add a query "byName" in addition to the find(), findOne() and findById() methods).

+ +

Using models

+ +

Once you've created a schema you can use it to create models. The model represents a collection of documents in the database that you can search, while the model's instances represent individual documents that you can save and retrieve.

+ +

We provide a brief overview below. For more information see: Models (Mongoose docs).

+ +

Creating and modifying documents

+ +

To create a record you can define an instance of the model and then call save(). The examples below assume SomeModel is a model (with a single field "name") that we have created from our schema.

+ +
// Create an instance of model SomeModel
+var awesome_instance = new SomeModel({ name: 'awesome' });
+
+// Save the new model instance, passing a callback
+awesome_instance.save(function (err) {
+  if (err) return handleError(err);
+  // saved!
+});
+
+ +

Creation of records (along with updates, deletes, and queries) are asynchronous operations — you supply a callback that is called when the operation completes. The API uses the error-first argument convention, so the first argument for the callback will always be an error value (or null). If the API returns some result, this will be provided as the second argument.

+ +

You can also use create() to define the model instance at the same time as you save it. The callback will return an error for the first argument and the newly-created model instance for the second argument.

+ +
SomeModel.create({ name: 'also_awesome' }, function (err, awesome_instance) {
+  if (err) return handleError(err);
+  // saved!
+});
+ +

Every model has an associated connection (this will be the default connection when you use mongoose.model()). You create a new connection and call .model() on it to create the documents on a different database.

+ +

You can access the fields in this new record using the dot syntax, and change the values. You have to call save() or update() to store modified values back to the database.

+ +
// Access model field values using dot notation
+console.log(awesome_instance.name); //should log 'also_awesome'
+
+// Change record by modifying the fields, then calling save().
+awesome_instance.name="New cool name";
+awesome_instance.save(function (err) {
+   if (err) return handleError(err); // saved!
+   });
+
+ +

Searching for records

+ +

You can search for records using query methods, specifying the query conditions as a JSON document. The code fragment below shows how you might find all athletes in a database that play tennis, returning just the fields for athlete name and age. Here we just specify one matching field (sport) but you can add more criteria, specify regular expression criteria, or remove the conditions altogether to return all athletes.

+ +
var Athlete = mongoose.model('Athlete', yourSchema);
+
+// find all athletes who play tennis, selecting the 'name' and 'age' fields
+Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) {
+  if (err) return handleError(err);
+  // 'athletes' contains the list of athletes that match the criteria.
+})
+ +

If you specify a callback, as shown above, the query will execute immediately. The callback will be invoked when the search completes.

+ +
+

Note: All callbacks in Mongoose use the pattern callback(error, result). If an error occurs executing the query, the error parameter will contain an error document, and result will be null. If the query is successful, the error parameter will be null, and the result will be populated with the results of the query.

+
+ +

If you don't specify a callback then the API will return a variable of type Query. You can use this query object to build up your query and then execute it (with a callback) later using the exec() method.

+ +
// find all athletes that play tennis
+var query = Athlete.find({ 'sport': 'Tennis' });
+
+// selecting the 'name' and 'age' fields
+query.select('name age');
+
+// limit our results to 5 items
+query.limit(5);
+
+// sort by age
+query.sort({ age: -1 });
+
+// execute the query at a later time
+query.exec(function (err, athletes) {
+  if (err) return handleError(err);
+  // athletes contains an ordered list of 5 athletes who play Tennis
+})
+ +

Above we've defined the query conditions in the find() method. We can also do this using a where() function, and we can chain all the parts of our query together using the dot operator (.) rather than adding them separately. The code fragment below is the same as our query above, with an additional condition for the age.

+ +
Athlete.
+  find().
+  where('sport').equals('Tennis').
+  where('age').gt(17).lt(50).  //Additional where query
+  limit(5).
+  sort({ age: -1 }).
+  select('name age').
+  exec(callback); // where callback is the name of our callback function.
+ +

The find() method gets all matching records, but often you just want to get one match. The following methods query for a single record:

+ + + +
+

Note: There is also a count() method that you can use to get the number of items that match conditions. This is useful if you want to perform a count without actually fetching the records.

+
+ +

There is a lot more you can do with queries. For more information see: Queries (Mongoose docs).

+ + + +

You can create references from one document/model instance to another using the ObjectId schema field, or from one document to many using an array of ObjectIds. The field stores the id of the related model. If you need the actual content of the associated document, you can use the populate() method in a query to replace the id with the actual data.

+ +

For example, the following schema defines authors and stories. Each author can have multiple stories, which we represent as an array of ObjectId. Each story can have a single author. The "ref" (highlighted in bold below) tells the schema which model can be assigned to this field.

+ +
var mongoose = require('mongoose')
+  , Schema = mongoose.Schema
+
+var authorSchema = Schema({
+  name    : String,
+  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
+});
+
+var storySchema = Schema({
+  author : { type: Schema.Types.ObjectId, ref: 'Author' },
+  title    : String
+});
+
+var Story  = mongoose.model('Story', storySchema);
+var Author = mongoose.model('Author', authorSchema);
+ +

We can save our references to the related document by assigning the _id value. Below we create an author, then a book, and assign the author id to our stories author field.

+ +
var bob = new Author({ name: 'Bob Smith' });
+
+bob.save(function (err) {
+  if (err) return handleError(err);
+
+  //Bob now exists, so lets create a story
+  var story = new Story({
+    title: "Bob goes sledding",
+    author: bob._id    // assign the _id from the our author Bob. This ID is created by default!
+  });
+
+  story.save(function (err) {
+    if (err) return handleError(err);
+    // Bob now has his story
+  });
+});
+ +

Our story document now has an author referenced by the author document's ID. In order to get the author information in our story results we use populate(), as shown below.

+ +
Story
+.findOne({ title: 'Bob goes sledding' })
+.populate('author') //This populates the author id with actual author information!
+.exec(function (err, story) {
+  if (err) return handleError(err);
+  console.log('The author is %s', story.author.name);
+  // prints "The author is Bob Smith"
+});
+ +
+

Note: Astute readers will have noted that we added an author to our story, but we didn't do anything to add our story to our author's stories array. How then can we get all stories by a particular author? One way would be to add our author to the stories array, but this would result in us having two places where the information relating authors and stories needs to be maintained.

+ +

A better way is to get the _id of our author, then use find() to search for this in the author field across all stories.

+ +
Story
+.find({ author : bob._id })
+.exec(function (err, stories) {
+  if (err) return handleError(err);
+  // returns all stories that have Bob's id as their author.
+});
+
+
+ +

This is almost everything you need to know about working with related items for this tutorial. For more detailed information see Population (Mongoose docs).

+ +

One schema/model per file

+ +

While you can create schemas and models using any file structure you like, we highly recommend defining each model schema in its own module (file), exporting the method to create the model. This is shown below:

+ +
// File: ./models/somemodel.js
+
+//Require Mongoose
+var mongoose = require('mongoose');
+
+//Define a schema
+var Schema = mongoose.Schema;
+
+var SomeModelSchema = new Schema({
+    a_string          : String,
+    a_date            : Date,
+});
+
+//Export function to create "SomeModel" model class
+module.exports = mongoose.model('SomeModel', SomeModelSchema );
+ +

You can then require and use the model immediately in other files. Below we show how you might use it to get all instances of the model.

+ +
//Create a SomeModel model just by requiring the module
+var SomeModel = require('../models/somemodel')
+
+// Use the SomeModel object (model) to find all SomeModel records
+SomeModel.find(callback_function);
+ +

Setting up the MongoDB database

+ +

Now that we understand something of what Mongoose can do and how we want to design our models, it's time to start work on the LocalLibrary website. The very first thing we want to do is set up a MongoDb database that we can use to store our library data.

+ +

For this tutorial we're going to use mLab's free cloud-hosted "sandbox" database. This database tier is not considered suitable for production websites because it has no redundancy, but it is great for development and prototyping. We're using it here because it is free and easy to set up, and because mLab is a popular database as a service vendor that you might reasonably choose for your production database (other popular choices at the time of writing include Compose, ScaleGrid and MongoDB Atlas).

+ +
+

Note: If you prefer you can set up a MongoDb database locally by downloading and installing the appropriate binaries for your system. The rest of the instructions in this article would be similar, except for the database URL you would specify when connecting.

+
+ +

You will first need to create an account with mLab (this is free, and just requires that you enter basic contact details and acknowledge their terms of service). 

+ +

After logging in, you'll be taken to the home screen:

+ +
    +
  1. Click Create New in the MongoDB Deployments section.
  2. +
  3. This will open the Cloud Provider Selection screen.
    + MLab - screen for new deployment
    + +
      +
    • Select the SANDBOX (Free) plan from the Plan Type section. 
    • +
    • Select any provider from the Cloud Provider section. Different providers offer different regions (displayed below the selected plan type).
    • +
    • Click the Continue button.
    • +
    +
  4. +
  5. This will open the Select Region screen. +

    Select new region screen

    + +
      +
    • +

      Select the region closest to you and then Continue.

      +
    • +
    +
  6. +
  7. +

    This will open the Final Details screen.
    + New deployment database name

    + +
      +
    • +

      Enter the name for the new database as local_library and then select Continue.

      +
    • +
    +
  8. +
  9. +

    This will open the Order Confirmation screen.
    + Order confirmation screen

    + +
      +
    • +

      Click Submit Order to create the database.

      +
    • +
    +
  10. +
  11. +

    You will be returned to the home screen. Click on the new database you just created to open its details screen. As you can see the database has no collections (data).
    + mLab - Database details screen
    +  
    + The URL that you need to use to access your database is displayed on the form above (shown for this database circled above). In order to use this you need to create a database user that you can specify in the URL.

    +
  12. +
  13. Click the Users tab and select the Add database user button.
  14. +
  15. Enter a username and password (twice), and then press Create. Do not select Make read only.
    +
  16. +
+ +

You now have now created the database, and have an URL (with username and password) that can be used to access it. This will look something like: mongodb://your_user_namer:your_password@ds119748.mlab.com:19748/local_library.

+ +

Install Mongoose

+ +

Open a command prompt and navigate to the directory where you created your skeleton Local Library website. Enter the following command to install Mongoose (and its dependencies) and add it to your package.json file, unless you have already done so when reading the Mongoose Primer above.

+ +
npm install mongoose --save
+
+ +

Connect to MongoDB

+ +

Open /app.js (in the root of your project) and copy the following text below where you declare the Express application object (after the line var app = express();). Replace the database url string ('insert_your_database_url_here') with the location URL representing your own database (i.e. using the information from from mLab).

+ +
//Set up mongoose connection
+var mongoose = require('mongoose');
+var mongoDB = 'insert_your_database_url_here';
+mongoose.connect(mongoDB);
+mongoose.Promise = global.Promise;
+var db = mongoose.connection;
+db.on('error', console.error.bind(console, 'MongoDB connection error:'));
+ +

As discussed in the Mongoose primer above, this code creates the default connection to the database and binds to the error event (so that errors will be printed to the console). 

+ +

Defining the LocalLibrary Schema

+ +

We will define a separate module for each model, as discussed above. Start by creating a folder for our models in the project root (/models) and then create separate files for each of the models:

+ +
/express-locallibrary-tutorial  //the project root
+  /models
+    author.js
+    book.js
+    bookinstance.js
+    genre.js
+
+ +

Author model

+ +

Copy the Author schema code shown below and paste it into your ./models/author.js file. The scheme defines an author has having String SchemaTypes for the first and family names, that are required and have a maximum of 100 characters, and Date fields for the date of birth and death.

+ +
var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var AuthorSchema = new Schema(
+  {
+    first_name: {type: String, required: true, max: 100},
+    family_name: {type: String, required: true, max: 100},
+    date_of_birth: {type: Date},
+    date_of_death: {type: Date},
+  }
+);
+
+// Virtual for author's full name
+AuthorSchema
+.virtual('name')
+.get(function () {
+  return this.family_name + ', ' + this.first_name;
+});
+
+// Virtual for author's URL
+AuthorSchema
+.virtual('url')
+.get(function () {
+  return '/catalog/author/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('Author', AuthorSchema);
+
+
+ +

We've also declared a virtual for the AuthorSchema named "url" that returns the absolute URL required to get a particular instance of the model — we'll use the property in our templates whenever we need to get a link to a particular author.

+ +
+

Note: Declaring our URLs as a virtual in the schema is a good idea because then the URL for an item only ever needs to be changed in one place.
+ At this point a link using this URL wouldn't work, because we haven't got any routes handling code for individual model instances. We'll set those up in a later article!

+
+ +

At the end of the module we export the model.

+ +

Book model

+ +

Copy the Book schema code shown below and paste it into your ./models/book.js file. Most of this is similar to the author model — we've declared a schema with a number of string fields and a virtual for getting the URL of specific book records, and we've exported the model.

+ +
var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var BookSchema = new Schema(
+  {
+    title: {type: String, required: true},
+    author: {type: Schema.ObjectId, ref: 'Author', required: true},
+    summary: {type: String, required: true},
+    isbn: {type: String, required: true},
+    genre: [{type: Schema.ObjectId, ref: 'Genre'}]
+  }
+);
+
+// Virtual for book's URL
+BookSchema
+.virtual('url')
+.get(function () {
+  return '/catalog/book/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('Book', BookSchema);
+
+ +

The main difference here is that we've created two references to other models:

+ + + +

BookInstance model

+ +

Finally, copy the BookInstance schema code shown below and paste it into your ./models/bookinstance.js file. The BookInstance represents a specific copy of a book that someone might borrow, and includes information about whether the copy is available or on what date it is expected back, "imprint" or version details.

+ +
var mongoose = require('mongoose');
+
+var Schema = mongoose.Schema;
+
+var BookInstanceSchema = new Schema(
+  {
+    book: { type: Schema.ObjectId, ref: 'Book', required: true }, //reference to the associated book
+    imprint: {type: String, required: true},
+    status: {type: String, required: true, enum: ['Available', 'Maintenance', 'Loaned', 'Reserved'], default: 'Maintenance'},
+    due_back: {type: Date, default: Date.now}
+  }
+);
+
+// Virtual for bookinstance's URL
+BookInstanceSchema
+.virtual('url')
+.get(function () {
+  return '/catalog/bookinstance/' + this._id;
+});
+
+//Export model
+module.exports = mongoose.model('BookInstance', BookInstanceSchema);
+ +

The new things we show here are the field options:

+ + + +

Everything else should be familiar from our previous schema.

+ +

Genre model - challenge!

+ +

Open your ./models/genre.js file and create a schema for storing genres (the category of book, e.g. whether it is fiction or non-fiction, romance or military history, etc).

+ +

The definition will be very similar to the other models:

+ + + +

Testing — create some items

+ +

That's it. We now have all models for the site set up!

+ +

In order to test the models (and to create some example books and other items that we can use in our next articles) we'll now run an independent script to create items of each type:

+ +
    +
  1. Download (or otherwise create) the file populatedb.js inside your express-locallibrary-tutorial directory (in the same level as package.json). + +
    +

    Note: You don't need to know how populatedb.js works; it just adds sample data into the database.

    +
    +
  2. +
  3. Enter the following commands in the project root to install the async module that is required by the script (we'll discuss this in later tutorials, ) +
    npm install async --save
    +
  4. +
  5. Run the script using node in your command prompt, passing in the URL of your MongoDB database (the same one you replaced the insert_your_database_url_here placeholder with, inside app.js earlier): +
    node populatedb <your mongodb url>​​​​
    +
  6. +
  7. The script should run through to completion, displaying items as it creates them in the terminal.
  8. +
+ +
+

Tip: Go to your database on mLab. You should now be able to drill down into individual collections of Books, Authors, Genres and BookInstances, and check out individual documents.

+
+ +

Summary

+ +

In this article we've learned a bit about databases and ORMs on Node/Express, and a lot about how Mongoose schema and models are defined. We then used this information to design and implement Book, BookInstance, Author and Genre models for the LocalLibrary website.

+ +

Last of all we tested our models by creating a number of instances (using a standalone script). In the next article we'll look at creating some pages to display these objects.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git a/files/ko/learn/server-side/express_nodejs/routes/index.html b/files/ko/learn/server-side/express_nodejs/routes/index.html new file mode 100644 index 0000000000..8d8618ca98 --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/routes/index.html @@ -0,0 +1,639 @@ +--- +title: 'Express Tutorial Part 4: Routes and controllers' +slug: Learn/Server-side/Express_Nodejs/routes +translation_of: Learn/Server-side/Express_Nodejs/routes +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}
+ +

이 튜토리얼에서 우리는 더미 핸들러 함수를 이용해 최종적으로 LocalLibrary 웹사이트에 쓰이게 될 모든 리소스 종단점라우팅 모듈 (url 핸들링 코드)를 설정해 볼 것입니다.이 작업을 통해 우리는 향후 문서에 쓰일 함수들을 모듈화된 라우트 핸들링 코드 구조로 제작하는 법을 배울 수 있습니다.또한 Express를 이용해 모듈화된 라우팅방법을 잘 이해할 수 있게 될 것입니다.

+ + + + + + + + + + + + +
사전조건:Express/Node introduction를 먼저 구독해주세요.이전 강의 주제를 완료해 주세요.( Express Tutorial Part3 : Mongoose Database 와 연동하기)
목표: +

 간단한 라우팅 함수 구현.

+ +

모든 URL 종단점 구성해보기.

+
+ +

개요

+ +

지난 튜토리얼에서 우리는 데이터베이스와의 상호작용을 위해서 Mongoose 모델을 정의 했으며 초기 도서관 기록들을  만들기 위해 단 하나의 스크립트 파일을 사용했습니다.이것으로 우리는 이제 사용자에게 정보를 제공을 위한 코드를 작성할 수 있게 되었습니다. 첫번째로 해야할 일은 어떠한 정보를 웹사이트 페이지에 노출시킬 지 정하는 것입니다.그 다음에  정보들을 반환하기 위한 적절한 URL을 정의하게 될 것입니다.

+ +

하단의 다이어그램은 HTTP를 통해 정보를 요청/반환을 작업할 경우 실현시켜야 하는  정보와 객체들의 주요 흐름을 나타내고 있습니다.In addition to the views and routes the diagram shows "controllers" — functions that separate out the code to route requests from the code that actually processes requests.

+ +

 

+ +

`이미 작성한 모델들을 제외한 우리가 앞으로 작성할 목록은 :

+ + + +

+ +

Ultimately we might have pages to show lists and detail information for books, genres, authors and bookinstances, along with pages to create, update, and delete records. That's a lot to document in one article. Therefore most of this article will concentrate on setting up our routes and controllers to return "dummy" content. We'll extend the controller methods in our subsequent articles to work with model data.

+ +

The first section below provides a brief "primer" on how to use the Express "Router" middleware. We'll then use that knowledge in the following sections when we set up the LocalLibrary routes.

+ +

Routes primer

+ +

A route is a section of Express code that associates an HTTP verb (GET, POST, PUT, DELETE, etc.), an URL path/pattern, and a function that is called to handle that pattern.

+ +

There are several ways to create routes. For this tutorial we're going to use the express.Router middleware as it allows us to group the route handlers for a particular part of a site together and access them using a common route-prefix. We'll keep all our library-related routes in a "catalog" module, and, if we add routes for handling user accounts or other functions, we can keep them grouped separately.

+ +
+

Note: We discussed Express application routes briefly in our Express Introduction > Creating route handlers. Other than providing better support for modularization (as discussed in the first subsection below), using Router is very similar to defining routes directly on the Express application object.

+
+ +

The rest of this section provides an overview of how the Router can be used to define the routes.

+ +

분리된 라우트 모듈들의 사용과 정의(Defining and using separate route modules)

+ +

The code below provides a concrete example of how we can create a route module and then use it in an Express application.

+ +

아래 코드는 우리가 어떻게 라우트 모듈을 생성하고  Express 어플리케이션에서 사용할 것인지에 대한 구체적인 예를 보여준다.

+ +

First we create routes for a wiki in a module named wiki.js. The code first imports the Express application object, uses it to get a Router object and then adds a couple of routes to it using the get() method. Last of all the module exports the Router object.

+ +

첫번재  우리는 wiki.js 를 이름을 가진 모듈에서 위키를 위한 라우트를 만든다. 첫번째 코드에서 Express 어플리케이션 객체가 중요하고, 이 객체를 라우트 오브젝트를 얻기 위해서 사용하고, get()메서드를 사용하여 라우트는 2개를 추가한다. 모듈에서 마지막에는 라우트 객체를 Export한다.

+ +
// wiki.js - Wiki route module
+
+var express = require('express')
+var router = express.Router()
+
+// Home page route
+router.get('/', function (req, res) {
+  res.send('Wiki home page')
+})
+
+// About page route
+router.get('/about', function (req, res) {
+  res.send('About this wiki')
+})
+
+module.exports = router
+
+
+ +
+

Note: Above we are defining our route handler callbacks directly in the router functions. In the LocalLibrary we'll define these callbacks in a separate controller module.

+
+ +

To use the router module in our main app file we first require() the route module (wiki.js). We then call use() on the Express application to add the Router to the middleware handling path, specifying an URL path of 'wiki'.

+ +
var wiki = require('./wiki.js')
+// ...
+app.use('/wiki', wiki)
+ +

The two routes defined in our wiki route module are then accessible from /wiki/ and /wiki/about/.

+ +

wiki 라우트 모듈에서 정희 두개의 라우트를 정의되면 /wiki그리고 /wiki/about/ 으로 접근가능해진다.

+ +

라우트 함수들(Route functions)

+ +

Our module above defines a couple of typical route functions. The "about" route (reproduced below) is defined using the Router.get() method, which responds only to HTTP GET requests. The first argument to this method is the URL path while the second is a callback function that will be invoked if an HTTP GET request with the path is received.

+ +
router.get('/about', function (req, res) {
+  res.send('About this wiki')
+})
+
+ +

The callback takes three arguments (usually named as shown: req, res, next), that will contain the HTTP Request object, HTTP response, and the next function in the middleware chain.

+ +
+

Note: Router functions are Express middleware, which means that they must either complete (respond to) the request or call the next function in the chain. In the case above we complete the request, so the next argument is not actually used.

+
+ +

The callback function here calls send() on the response to return the string "About this wiki" when we receive a GET request with the path ('/about'). There are a number of other response methods for ending the request/response cycle. For example, you could call res.json() to send a JSON response or res.sendFile() to send a file. The response method that we'll be using most often as we build up the library is render(), which creates and returns HTML files using templates and data—we'll talk a lot more about that in a later article!

+ +

HTTP verbs

+ +

The example routes above use the Router.get() method to respond to HTTP GET requests with a certain path.

+ +

The Router also provides route methods for all the other HTTP verbs, that are mostly used in exactly the same way: post(), put(), delete(), options(), trace(), copy(), lock(), mkcol(), move(), purge(), propfind(), proppatch(), unlock(), report(), ​​​​​​ mkactivity(), checkout(), merge(), m-search(), notify(), subscribe(), unsubscribe(), patch(), search(), and connect().

+ +

For example, the code below behaves just like the previous /about route, but only responds to HTTP POST requests.

+ +
router.post('/about', function (req, res) {
+  res.send('About this wiki')
+})
+ +

라우트 경로들(Route paths)

+ +

The route paths define the endpoints at which requests can be made. The examples we've seen so far have just been strings, and are used exactly as written: '/', '/about', '/book', '/any-random.path'.

+ +

Route paths can also be string patterns. String patterns use a subset of regular expression syntax to define patterns of endpoints that will be matched. The subset is listed below (note that the hyphen (-) and the dot (.) are interpreted literally by string-based paths):

+ + + +

The route paths can also be JavaScript regular expressions. For example, the route path below will match match catfish and dogfish, but not catflap, catfishhead, and so on. Note that the path for a regular expression uses regular expression syntax (it is not a quoted string as in the previous cases).

+ +
app.get(/.*fish$/, function (req, res) {
+  ...
+})
+ +
+

Note: Most of our routes for the LocalLibrary will simply use strings and not string patterns and regular expressions. We'll also use route parameters as discussed in the next section.

+
+ +

라우트 파라미터들(Route parameters)

+ +

Route parameters are named URL segments used to capture the values specified at their position in the URL. The named segments are prefixed with a colon and then the name (e.g. /:your_parameter_name/. The captured values are stored in the req.params object using the parameter names as keys (e.g. req.params.your_parameter_name).

+ +

So for example, consider a URL encoded to contain information about users and books: http://localhost:3000/users/34/books/8989. We can extract this information as shown below, with the userId and bookId path parameters:

+ +
app.get('/users/:userId/books/:bookId', function (req, res) {
+  // Access userId via: req.params.userId
+  // Access bookId via: req.params.bookId
+  res.send(req.params)
+})
+
+ +

The names of route parameters must be made up of “word characters” (A-Z, a-z, 0-9, and _).

+ +
+

Note: The URL /book/create will be matched by a route like /book/:bookId (which will extract a "bookId" value of 'create'). The first route that matches an incoming URL will be used, so if you want to process /book/create URLs separately, their route handler must be defined before your /book/:bookId route.

+
+ +

That's all you need to get started with routes - if needed you can find more information in the Express docs: Basic routing and Routing guide. The following sections show how we'll set up our routes and controllers for the LocalLibrary.

+ +

Routes needed for the LocalLibrary

+ +

The URLs that we're ultimately going to need for our pages are listed below, where object is replaced by the name of each of our models (book, bookinstance, genre, author), objects is the plural of object, and id is the unique instance field (_id) that is given to each Mongoose model instance by default.

+ + + +

The first home page and list pages don't encode any additional information. While the results returned will depend on the model type and the content in the database, the queries run to get the information will always be the same (similarly the code run for object creation will always be similar).

+ +

By contrast the other URLs are used to act on a specific document/model instance—these encode the identity of the item in the URL (shown as <id> above). We'll use path parameters to extract the encoded information and pass it to the route handler (and in a later article we'll use this to dynamically determine what information to get from the database). By encoding the information in our URL we only need one route for every resource of a particular type (e.g. one route to handle the display of every single book item).

+ +
+

Note: Express allows you to construct your URLs any way you like — you can encode information in the body of the URL as shown above or use URL GET parameters (e.g. /book/?id=6). Whichever approach you use, the URLs should be kept clean, logical and readable (check out the W3C advice here).

+
+ +

Next we create our route handler callback functions and route code for all the above URLs.

+ +

Create the route-handler callback functions

+ +

Before we define our routes, we'll first create all the dummy/skeleton callback functions that they will invoke. The callbacks will be stored in separate "controller" modules for Books, BookInstances, Genres, and Authors (you can use any file/module structure, but this seems an appropriate granularity for this project).

+ +

Start by creating a folder for our controllers in the project root (/controllers) and then create separate controller files/modules for handling each of the models:

+ +
/express-locallibrary-tutorial  //the project root
+  /controllers
+    authorController.js
+    bookController.js
+    bookinstanceController.js
+    genreController.js
+ +

Author controller

+ +

Open the /controllers/authorController.js file and copy in the following code:

+ +
var Author = require('../models/author');
+
+// Display list of all Authors
+exports.author_list = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author list');
+};
+
+// Display detail page for a specific Author
+exports.author_detail = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author detail: ' + req.params.id);
+};
+
+// Display Author create form on GET
+exports.author_create_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author create GET');
+};
+
+// Handle Author create on POST
+exports.author_create_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author create POST');
+};
+
+// Display Author delete form on GET
+exports.author_delete_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author delete GET');
+};
+
+// Handle Author delete on POST
+exports.author_delete_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author delete POST');
+};
+
+// Display Author update form on GET
+exports.author_update_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author update GET');
+};
+
+// Handle Author update on POST
+exports.author_update_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Author update POST');
+};
+
+ +

The module first requires the model that we'll later be using to access and update our data. It then exports functions for each of the URLs we wish to handle (the create, update and delete operations use forms, and hence also have additional methods for handling form post requests — we'll discuss those methods in the "forms article" later on).

+ +

All the functions have the standard form of an Express middleware function, with arguments for the request, response, and the next function to be called if the method does not complete the request cycle (in all these cases it does!). The methods simply return a string indicating that the associated page has not yet been created. If a controller function is expected to receive path parameters, these are included in the message string.

+ +

BookInstance controller

+ +

Open the /controllers/bookinstanceController.js file and copy in the following code (this follows an identical pattern to the Author controller module):

+ +
var BookInstance = require('../models/bookinstance');
+
+// Display list of all BookInstances
+exports.bookinstance_list = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance list');
+};
+
+// Display detail page for a specific BookInstance
+exports.bookinstance_detail = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance detail: ' + req.params.id);
+};
+
+// Display BookInstance create form on GET
+exports.bookinstance_create_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance create GET');
+};
+
+// Handle BookInstance create on POST
+exports.bookinstance_create_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance create POST');
+};
+
+// Display BookInstance delete form on GET
+exports.bookinstance_delete_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance delete GET');
+};
+
+// Handle BookInstance delete on POST
+exports.bookinstance_delete_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance delete POST');
+};
+
+// Display BookInstance update form on GET
+exports.bookinstance_update_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance update GET');
+};
+
+// Handle bookinstance update on POST
+exports.bookinstance_update_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: BookInstance update POST');
+};
+
+ +

Genre controller

+ +

Open the /controllers/genreController.js file and copy in the following text (this follows an identical pattern to the Author and BookInstance files):

+ +
var Genre = require('../models/genre');
+
+// Display list of all Genre
+exports.genre_list = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre list');
+};
+
+// Display detail page for a specific Genre
+exports.genre_detail = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre detail: ' + req.params.id);
+};
+
+// Display Genre create form on GET
+exports.genre_create_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre create GET');
+};
+
+// Handle Genre create on POST
+exports.genre_create_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre create POST');
+};
+
+// Display Genre delete form on GET
+exports.genre_delete_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre delete GET');
+};
+
+// Handle Genre delete on POST
+exports.genre_delete_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre delete POST');
+};
+
+// Display Genre update form on GET
+exports.genre_update_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre update GET');
+};
+
+// Handle Genre update on POST
+exports.genre_update_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Genre update POST');
+};
+
+ +

Book controller

+ +

Open the /controllers/bookController.js file and copy in the following code. This follows the same pattern as the other controller modules, but additionally has an index() function for displaying the site welcome page:

+ +
var Book = require('../models/book');
+
+exports.index = function(req, res) {
+    res.send('NOT IMPLEMENTED: Site Home Page');
+};
+
+// Display list of all books
+exports.book_list = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book list');
+};
+
+// Display detail page for a specific book
+exports.book_detail = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book detail: ' + req.params.id);
+};
+
+// Display book create form on GET
+exports.book_create_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book create GET');
+};
+
+// Handle book create on POST
+exports.book_create_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book create POST');
+};
+
+// Display book delete form on GET
+exports.book_delete_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book delete GET');
+};
+
+// Handle book delete on POST
+exports.book_delete_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book delete POST');
+};
+
+// Display book update form on GET
+exports.book_update_get = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book update GET');
+};
+
+// Handle book update on POST
+exports.book_update_post = function(req, res) {
+    res.send('NOT IMPLEMENTED: Book update POST');
+};
+
+ +

Create the catalog route module

+ +

Next we create routes for all the URLs needed by the LocalLibrary website, which will call the controller functions we defined in the previous section.

+ +

The skeleton already has a ./routes folder containing routes for the index and users. Create another route file — catalog.js — inside this folder, as shown.

+ +
/express-locallibrary-tutorial //the project root
+  /routes
+    index.js
+    users.js
+    catalog.js
+ +

Open /routes/catalog.js and copy in the code below:

+ +
var express = require('express');
+var router = express.Router();
+
+// Require controller modules
+var book_controller = require('../controllers/bookController');
+var author_controller = require('../controllers/authorController');
+var genre_controller = require('../controllers/genreController');
+var book_instance_controller = require('../controllers/bookinstanceController');
+
+/// BOOK ROUTES ///
+
+/* GET catalog home page. */
+router.get('/', book_controller.index);
+
+/* GET request for creating a Book. NOTE This must come before routes that display Book (uses id) */
+router.get('/book/create', book_controller.book_create_get);
+
+/* POST request for creating Book. */
+router.post('/book/create', book_controller.book_create_post);
+
+/* GET request to delete Book. */
+router.get('/book/:id/delete', book_controller.book_delete_get);
+
+// POST request to delete Book
+router.post('/book/:id/delete', book_controller.book_delete_post);
+
+/* GET request to update Book. */
+router.get('/book/:id/update', book_controller.book_update_get);
+
+// POST request to update Book
+router.post('/book/:id/update', book_controller.book_update_post);
+
+/* GET request for one Book. */
+router.get('/book/:id', book_controller.book_detail);
+
+/* GET request for list of all Book items. */
+router.get('/books', book_controller.book_list);
+
+/// AUTHOR ROUTES ///
+
+/* GET request for creating Author. NOTE This must come before route for id (i.e. display author) */
+router.get('/author/create', author_controller.author_create_get);
+
+/* POST request for creating Author. */
+router.post('/author/create', author_controller.author_create_post);
+
+/* GET request to delete Author. */
+router.get('/author/:id/delete', author_controller.author_delete_get);
+
+// POST request to delete Author
+router.post('/author/:id/delete', author_controller.author_delete_post);
+
+/* GET request to update Author. */
+router.get('/author/:id/update', author_controller.author_update_get);
+
+// POST request to update Author
+router.post('/author/:id/update', author_controller.author_update_post);
+
+/* GET request for one Author. */
+router.get('/author/:id', author_controller.author_detail);
+
+/* GET request for list of all Authors. */
+router.get('/authors', author_controller.author_list);
+
+/// GENRE ROUTES ///
+
+/* GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id) */
+router.get('/genre/create', genre_controller.genre_create_get);
+
+/* POST request for creating Genre. */
+router.post('/genre/create', genre_controller.genre_create_post);
+
+/* GET request to delete Genre. */
+router.get('/genre/:id/delete', genre_controller.genre_delete_get);
+
+// POST request to delete Genre
+router.post('/genre/:id/delete', genre_controller.genre_delete_post);
+
+/* GET request to update Genre. */
+router.get('/genre/:id/update', genre_controller.genre_update_get);
+
+// POST request to update Genre
+router.post('/genre/:id/update', genre_controller.genre_update_post);
+
+/* GET request for one Genre. */
+router.get('/genre/:id', genre_controller.genre_detail);
+
+/* GET request for list of all Genre. */
+router.get('/genres', genre_controller.genre_list);
+
+/// BOOKINSTANCE ROUTES ///
+
+/* GET request for creating a BookInstance. NOTE This must come before route that displays BookInstance (uses id) */
+router.get('/bookinstance/create', book_instance_controller.bookinstance_create_get);
+
+/* POST request for creating BookInstance. */
+router.post('/bookinstance/create', book_instance_controller.bookinstance_create_post);
+
+/* GET request to delete BookInstance. */
+router.get('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_get);
+
+// POST request to delete BookInstance
+router.post('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_post);
+
+/* GET request to update BookInstance. */
+router.get('/bookinstance/:id/update', book_instance_controller.bookinstance_update_get);
+
+// POST request to update BookInstance
+router.post('/bookinstance/:id/update', book_instance_controller.bookinstance_update_post);
+
+/* GET request for one BookInstance. */
+router.get('/bookinstance/:id', book_instance_controller.bookinstance_detail);
+
+/* GET request for list of all BookInstance. */
+router.get('/bookinstances', book_instance_controller.bookinstance_list);
+
+module.exports = router;
+
+ +

The module requires Express and then uses it to create a Router object. The routes are all set up on the router, which is then exported.

+ +

The routes are defined either using .get() or .post() methods on the router object. All the paths are defined using strings (we don't use string patterns or regular expressions), routes that act on some specific resource (e.g. book) use path parameters to get the object id from the URL.

+ +

The handler functions are all imported from the controller modules we created in the previous section.

+ +

Update the index route module

+ +

We've set up all our new routes, but we still have a route to the original page. Let's instead redirect this to the new index page that we've created at the path '/catalog'.

+ +

Open /routes/index.js and replace the existing route with the function below.

+ +
/* GET home page. */
+router.get('/', function(req, res) {
+  res.redirect('/catalog');
+});
+ +
+

Note: This is our first use of the redirect() response method. This redirects to the specified page, by default sending HTTP status code "302 Found". You can change the status code returned if needed, and supply either absolute or relative paths.

+
+ +

Update app.js

+ +

The last step is to add the routes to the middleware chain. We do this in app.js.

+ +

Open app.js and require the catalog route below the other routes (add the third line shown below, underneath the other two):

+ +
var index = require('./routes/index');
+var users = require('./routes/users');
+var catalog = require('./routes/catalog');  //Import routes for "catalog" area of site
+ +

Next, add the catalog route to the middleware stack below the other routes (add the third line shown below, underneath the other two):

+ +
app.use('/', index);
+app.use('/users', users);
+app.use('/catalog', catalog);  // Add catalog routes to middleware chain.
+ +
+

Note: We have added our catalog module at a path '/catalog'. This is prepended to all of the paths defined in the catalog module. So for example, to access a list of books, the URL will be: /catalog/books/.

+
+ +

That's it. We should now have routes and skeleton functions enabled for all the URLs that we will eventually support on the LocalLibrary website.

+ +

Testing the routes

+ +

To test the routes, first start the website using your usual approach

+ + + +

Then navigate to a number of LocalLibrary URLs, and verify that you don't get an error page (HTTP 404). A small set of URLs are listed below for your convenience:

+ + + +

Summary

+ +

We've now created all the routes for our site, along with dummy controller functions that we can populate with a full implementation in later articles. Along the way we've learned a lot of fundamental information about Express routes, and some approaches for structuring our routes and controllers.

+ +

In our next article we'll create a proper welcome page for the site, using views (templates) and information stored in our models.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}

diff --git "a/files/ko/learn/server-side/express_nodejs/\352\260\234\353\260\234_\355\231\230\352\262\275/index.html" "b/files/ko/learn/server-side/express_nodejs/\352\260\234\353\260\234_\355\231\230\352\262\275/index.html" new file mode 100644 index 0000000000..b8c8db8ffa --- /dev/null +++ "b/files/ko/learn/server-side/express_nodejs/\352\260\234\353\260\234_\355\231\230\352\262\275/index.html" @@ -0,0 +1,403 @@ +--- +title: Node 개발 환경을 설치하기 +slug: Learn/Server-side/Express_Nodejs/개발_환경 +tags: + - CodingScripting + - Express + - Node + - nodejs + - npm + - 개발 환경 + - 배움 + - 서버-사이드 + - 인트로 + - 초보자 +translation_of: Learn/Server-side/Express_Nodejs/development_environment +--- +
{{LearnSidebar}}
+ +
{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}
+ +

이제 Express에 관한 내용을 알았으니, Windows, Linux (Ubuntu), 그리고 macOS 에서의 Node/Express 개발 환경을 설정하고 테스트하는 법을 보여드리겠습니다. 사용중인 운영 체제가 무엇이든 간에, 이 글은 당신에게 Express 앱 개발을 시작할 수 있도록 필요한 내용을 제공합니다.

+ + + + + + + + + + + + +
전제 조건:터미널 혹은 명령어 창을 여는 방법. 당신의 개발 컴퓨터의 운영 체제에 소프트웨어 패키지를 설치하는 방법을 알고 있어야 합니다.
목표:당신의 컴퓨터에 Express (X.XX) 을 위한 개발 환경을 설치하는 것.
+ +

Express 개발 환경 개요

+ +

Node and Express make it very easy to set up your computer in order to start developing web applications. This section provides an overview of what tools are needed, explains some of the simplest methods for installing Node (and Express) on Ubuntu, macOS, and Windows, and shows how you can test your installation.

+ +

Express 개발 환경이란 무엇입니까?

+ +

The Express development environment includes an installation of Nodejs, the NPM package manager, and (optionally) the Express Application Generator on your local computer.

+ +

Node and the NPM package manager are installed together from prepared binary packages, installers, operating system package managers or from source (as shown in the following sections). Express is then installed by NPM as a dependency of your individual Express web applications (along with other libraries like template engines, database drivers, authentication middleware, middleware to serve static files, etc.)

+ +

NPM can also be used to (globally) install the Express Application Generator, a handy tool for creating skeleton Express web apps that follow the MVC pattern. The application generator is optional because you don't need to use this tool to create apps that use Express, or construct Express apps that have the same architectural layout or dependencies. We'll be using it though, because it makes getting started a lot easier, and promotes a modular application structure.

+ +
+

Note: Unlike for some other web frameworks, the development environment does not include a separate development web server. In Node/Express a web application creates and runs its own web server!

+
+ +

There are other peripheral tools that are part of a typical development environment, including text editors or IDEs for editing code, and source control management tools like Git for safely managing different versions of your code. We are assuming that you've already got these sorts of tools installed (in particular a text editor).

+ +

What operating systems are supported?

+ +

Node can be run on Windows, macOS, many "flavours" of Linux, Docker, etc. (there is a full list on the nodejs Downloads page). Almost any personal computer should have the necessary performance to run Node during development. Express is run in a Node environment, and hence can run on any platform that runs Node.

+ +

In this article we provide setup instructions for Windows, macOS, and Ubuntu Linux.

+ +

What version of Node/Express should you use?

+ +

There are many releases of Node — newer releases contain bug fixes, support for more recent versions of ECMAScript (JavaScript) standards, and improvements to the Node APIs. 

+ +

Generally you should use the most recent LTS (long-term supported) release as this will be more stable than the "current" release while still having relatively recent features (and is still being actively maintained). You should use the Current release if you need a feature that is not present in the LTS version.

+ +

For Express you should always use the latest version.

+ +

What about databases and other dependencies?

+ +

Other dependencies, such as database drivers, template engines, authentication engines, etc. are part of the application, and are imported into the application environment using the NPM package manager.  We'll discuss them in later app-specific articles.

+ +

Node 설치하기

+ +

In order to use Express you will first have to install Nodejs and the Node Package Manager (NPM) on your operating system. The following sections explain the easiest way to install the Long Term Supported (LTS) version of Nodejs on Ubuntu Linux 16.04, macOS, and Windows 10.

+ +
+

Tip: The sections below show the easiest way to install Node and NPM on our target OS platforms. If you're using another OS or just want to see some of the other approaches for the current platforms then see Installing Node.js via package manager (nodejs.org).

+
+ +

Windows and macOS

+ +

Installing Node and NPM on Windows and macOS is straightforward because you can just use the provided installer:

+ +
    +
  1. Download the required installer: +
      +
    1. Go to https://nodejs.org/en/
    2. +
    3. Select the button to download the LTS build that is "Recommended for most users".
    4. +
    +
  2. +
  3. Install Node by double-clicking on the downloaded file and following the installation prompts.
  4. +
+ +

Ubuntu 18.04

+ +

The easiest way to install the most recent LTS version of Node 10.x is to use the package manager to get it from the Ubuntu binary distributions repository. This can be done very simply by running the following two commands on your terminal:

+ +
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
+sudo apt-get install -y nodejs
+
+ +
+

Warning: Don't install directly from the normal Ubuntu repositories because they contain very old versions of node.

+
+ +
    +
+ +

Testing your Nodejs and NPM installation

+ +

The easiest way to test that node is installed is to run the "version" command in your terminal/command prompt and check that a version string is returned:

+ +
>node -v
+v10.15.1
+ +

The Nodejs package manager NPM should also have been installed, and can be tested in the same way:

+ +
>npm -v
+6.4.1
+ +

As a slightly more exciting test let's create a very basic "pure node" server that simply prints out "Hello World" in the browser when you visit the correct URL in your browser:

+ +
    +
  1. Copy the following text into a file named hellonode.js. This uses pure Node features (nothing from Express) and some ES6 syntax: + +
    //Load HTTP module
    +const http = require("http");
    +const hostname = '127.0.0.1';
    +const port = 3000;
    +
    +//Create HTTP server and listen on port 3000 for requests
    +const server = http.createServer((req, res) => {
    +
    +  //Set the response HTTP header with HTTP status and Content type
    +  res.statusCode = 200;
    +  res.setHeader('Content-Type', 'text/plain');
    +  res.end('Hello World\n');
    +});
    +
    +//listen for request on port 3000, and as a callback function have the port listened on logged
    +server.listen(port, hostname, () => {
    +  console.log(`Server running at http://${hostname}:${port}/`);
    +});
    +
    + +

    The code imports the "http" module and uses it to create a server (createServer()) that listens for HTTP requests on port 3000. The script then prints a message to the console about what browser URL you can use to test the server. The createServer() function takes as an argument a callback function that will be invoked when an HTTP request is received — this simply returns a response with an HTTP status code of 200 ("OK") and the plain text "Hello World".

    + +
    +

    Note:  Don't worry if you don't understand exactly what this code is doing yet! We'll explain our code in greater detail once we start using Express!

    +
    +
  2. +
  3. Start the server by navigating into the same directory as your hellonode.js file in your command prompt, and calling node along with the script name, like so: +
    >node hellonode.js
    +Server running at http://127.0.0.1:3000/
    +
    +
  4. +
  5. Navigate to the URL http://127.0.0.1:3000 . If everything is working, the browser should simply display the string "Hello World".
  6. +
+ +

Using NPM

+ +

Next to Node itself, NPM is the most important tool for working with Node applications. NPM is used to fetch any packages (JavaScript libraries) that an application needs for development, testing, and/or production, and may also be used to run tests and tools used in the development process. 

+ +
+

Note: From Node's perspective, Express is just another package that you need to install using NPM and then require in your own code.

+
+ +

You can manually use NPM to separately fetch each needed package. Typically we instead manage dependencies using a plain-text definition file named package.json. This file lists all the dependencies for a specific JavaScript "package", including the package's name, version, description, initial file to execute, production dependencies, development dependencies, versions of Node it can work with, etc. The package.json file should contain everything NPM needs to fetch and run your application (if you were writing a reusable library you could use this definition to upload your package to the npm respository and make it available for other users).

+ +

Adding dependencies

+ +

The following steps show how you can use NPM to download a package, save it into the project dependencies, and then require it in a Node application.

+ +
+

Note: Here we show the instructions to fetch and install the Express package. Later on we'll show how this package, and others, are already specified for us using the Express Application Generator. This section is provided because it is useful to understand how NPM works and what is being created by the application generator.

+
+ +
    +
  1. First create a directory for your new application and navigate into it: +
    mkdir myapp
    +cd myapp
    +
  2. +
  3. Use the npm init command to create a package.json file for your application. This command prompts you for a number of things, including the name and version of your application and the name of the initial entry point file (by default this is index.js). For now, just accept the defaults: +
    npm init
    + +

    If you display the package.json file (cat package.json), you will see the defaults that you accepted, ending with the license.

    + +
    {
    +  "name": "myapp",
    +  "version": "1.0.0",
    +  "description": "",
    +  "main": "index.js",
    +  "scripts": {
    +    "test": "echo \"Error: no test specified\" && exit 1"
    +  },
    +  "author": "",
    +  "license": "ISC"
    +}
    +
    +
  4. +
  5. Now install Express in the myapp directory and save it in the dependencies list of your package.json file
  6. +
  7. +
    npm install express
    + +

    The dependencies section of your package.json will now appear at the end of the package.json file and will include Express.

    + +
    {
    +  "name": "myapp",
    +  "version": "1.0.0",
    +  "description": "",
    +  "main": "index.js",
    +  "scripts": {
    +    "test": "echo \"Error: no test specified\" && exit 1"
    +  },
    +  "author": "",
    +  "license": "ISC",
    +  "dependencies": {
    +    "express": "^4.16.4"
    +  }
    +}
    +
    +
  8. +
  9. To use the Express library you call the require() function in your index.js file to include it in your application. Create this file now, in the root of the "myapp" application directory, and give it the following contents: +
    const express = require('express')
    +const app = express();
    +
    +app.get('/', (req, res) => {
    +  res.send('Hello World!')
    +});
    +
    +app.listen(8000, () => {
    +  console.log('Example app listening on port 8000!')
    +});
    +
    + +

    This code shows a minimal "HelloWorld" Express web application. This imports the "express" module using require() and uses it to create a server (app) that listens for HTTP requests on port 8000 and prints a message to the console explaining what browser URL you can use to test the server. The app.get() function only responds to HTTP GET requests with the specified URL path ('/'), in this case by calling a function to send our Hello World! message.

    +
  10. +
  11. You can start the server by calling node with the script in your command prompt: +
    >node index.js
    +Example app listening on port 8000
    +
    +
  12. +
  13. Navigate to the URL (http://127.0.0.1:8000/). If everything is working, the browser should simply display the string "Hello World!".
  14. +
+ +

Development dependencies

+ +

If a dependency is only used during development, you should instead save it as a "development dependency" (so that your package users don't have to install it in production). For example, to use the popular JavaScript Linting tool eslint you would call NPM as shown:

+ +
npm install eslint --save-dev
+ +

The following entry would then be added to your application's package.json:

+ +
  "devDependencies": {
+    "eslint": "^4.12.1"
+  }
+
+ +
+

Note: "Linters" are tools that perform static analysis on software in order to recognise and report adherence/non-adherance to some set of coding best practice.

+
+ +

Running tasks

+ +

In addition to defining and fetching dependencies you can also define named scripts in your package.json files and call NPM to execute them with the run-script command. This approach is commonly used to automate running tests and parts of the development or build toolchain (e.g., running tools to minify JavaScript, shrink images, LINT/analyse your code, etc).

+ +
+

Note: Task runners like Gulp and Grunt can also be used to run tests and other external tools.

+
+ +

For example, to define a script to run the eslint development dependency that we specified in the previous section we might add the following script block to our package.json file (assuming that our application source is in a folder /src/js):

+ +
"scripts": {
+  ...
+  "lint": "eslint src/js"
+  ...
+}
+
+ +

To explain a little further, eslint src/js is a command that we could enter in our terminal/command line to run eslint on JavaScript files contained in the src/js directory inside our app directory. Including the above inside our app's package.json file provides a shortcut for this command — lint.

+ +

We would then be able to run eslint using NPM by calling:

+ +
npm run-script lint
+# OR (using the alias)
+npm run lint
+
+ +

This example may not look any shorter than the original command, but you can include much bigger commands inside your npm scripts, including chains of multiple commands. You could identify a single npm script that runs all your tests at once.

+ +

Installing the Express Application Generator

+ +

The Express Application Generator tool generates an Express application "skeleton". Install the generator using NPM as shown (the -g flag installs the tool globally so that you can call it from anywhere):

+ +
npm install express-generator -g
+ +

To create an Express app named "helloworld" with the default settings, navigate to where you want to create it and run the app as shown:

+ +
express helloworld
+ +
+

Note: You can also specify the template library to use and a number of other settings. Use the help command to see all the options:

+ +
express --help
+
+
+ +

NPM will create the new Express app in a sub folder of your current location, displaying build progress on the console. On completion, the tool will display the commands you need to enter to install the Node dependencies and start the app.

+ +
+

The new app will have a package.json file in its root directory. You can open this to see what dependencies are installed, including Express and the template library Jade:

+ +
{
+  "name": "helloworld",
+  "version": "0.0.0",
+  "private": true,
+  "scripts": {
+    "start": "node ./bin/www"
+  },
+  "dependencies": {
+    "cookie-parser": "~1.4.3",
+    "debug": "~2.6.9",
+    "express": "~4.16.0",
+    "http-errors": "~1.6.2",
+    "jade": "~1.11.0",
+    "morgan": "~1.9.0"
+  }
+}
+
+ +

 

+
+ +

Install all the dependencies for the helloworld app using NPM as shown:

+ +
cd helloworld
+npm install
+
+ +

Then run the app (the commands are slightly different for Windows and Linux/macOS), as shown below:

+ +
# Run the helloworld on Windows with Command Prompt
+SET DEBUG=helloworld:* & npm start
+
+# Run the helloworld on Windows with PowerShell
+SET DEBUG=helloworld:* | npm start
+
+# Run helloworld on Linux/macOS
+DEBUG=helloworld:* npm start
+
+ +

The DEBUG command creates useful logging, resulting in an output like that shown below.

+ +
>SET DEBUG=helloworld:* & npm start
+
+> helloworld@0.0.0 start D:\Github\expresstests\helloworld
+> node ./bin/www
+
+  helloworld:server Listening on port 3000 +0ms
+ +

Open a browser and navigate to http://127.0.0.1:3000/ to see the default Express welcome page.

+ +

Express - Generated App Default Screen

+ +

We'll talk more about the generated app when we get to the article on generating a skeleton application.

+ + + +

Summary

+ +

You now have a Node development environment up and running on your computer that can be used for creating Express web applications. You've also seen how NPM can be used to import Express into an application, and also how you can create applications using the Express Application Generator tool and then run them.

+ +

In the next article we start working through a tutorial to build a complete web application using this environment and associated tools.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}

+ +

 

+ +

In this module

+ + + +

 

diff --git "a/files/ko/learn/server-side/express_nodejs/\354\212\244\354\274\210\353\240\210\355\206\244_\354\233\271\354\202\254\354\235\264\355\212\270/index.html" "b/files/ko/learn/server-side/express_nodejs/\354\212\244\354\274\210\353\240\210\355\206\244_\354\233\271\354\202\254\354\235\264\355\212\270/index.html" new file mode 100644 index 0000000000..ca72e39124 --- /dev/null +++ "b/files/ko/learn/server-side/express_nodejs/\354\212\244\354\274\210\353\240\210\355\206\244_\354\233\271\354\202\254\354\235\264\355\212\270/index.html" @@ -0,0 +1,512 @@ +--- +title: 'Express Tutorial Part 2: 스켈레톤 웹사이트 만들기' +slug: Learn/Server-side/Express_Nodejs/스켈레톤_웹사이트 +translation_of: Learn/Server-side/Express_Nodejs/skeleton_website +--- +
{{LearnSidebar}}
+ +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}

+ +

This second article in our Express Tutorial shows how you can create a "skeleton" website project which you can then go on to populate with site-specific routes, templates/views, and database calls.

+ + + + + + + + + + + + +
Prerequisites:Set up a Node development environment. Review the Express Tutorial.
Objective:Express 앱 제너레이터를 사용하여 자신만의 새로운 웹사이트 프로젝트를 시작할 수 있다.
+ +

Overview

+ +

이 아티클은 당신이 Express Application Generator 도구를 이용하여 스켈레톤(최소한의 프레임 모형만 갖춘) 웹사이트를 만드는 방법을 보여줍니다. 이는 사이트에 맞춘 라우트, 뷰/템플릿 그리고 데이터 베이스를 사용할 수 있게 합니다. In this case, we'll use the tool to create the framework for our Local Library website, to which we'll later add all the other code needed by the site. The process is extremely simple, requiring only that you invoke the generator on the command line with a new project name, optionally also specifying the site's template engine and CSS generator.

+ +

The following sections show you how to call the application generator, and provides a little explanation about the different view/CSS options. We'll also explain how the skeleton website is structured. At the end, we'll show how you can run the website to verify that it works.

+ +
+

Note: The Express Application Generator is not the only generator for Express applications, and the generated project is not the only viable way to structure your files and directories. The generated site does however have a modular structure that is easy to extend and understand. For information about a minimal Express application, see Hello world example (Express docs).

+
+ +

Using the application generator

+ +

You should already have installed the generator as part of setting up a Node development environment. As a quick reminder, you install the generator tool site-wide using the NPM package manager, as shown:

+ +
npm install express-generator -g
+ +

The generator has a number of options, which you can view on the command line using the --help (or -h) command:

+ +
> express --help
+
+    Usage: express [options] [dir]
+
+
+  Options:
+
+        --version        output the version number
+    -e, --ejs            add ejs engine support
+        --pug            add pug engine support
+        --hbs            add handlebars engine support
+    -H, --hogan          add hogan.js engine support
+    -v, --view <engine>  add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
+        --no-view        use static html instead of view engine
+    -c, --css <engine>   add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
+        --git            add .gitignore
+    -f, --force          force on non-empty directory
+    -h, --help           output usage information
+
+ +

You can simply specify express to create a project inside the current directory using the Jade view engine and plain CSS (if you specify a directory name then the project will be created in a sub-folder with that name).

+ +
express
+ +

You can also choose a view (template) engine using --view and/or a CSS generation engine using --css.

+ +
+

Note: The other options for choosing template engines (e.g. --hogan, --ejs, --hbs etc.) are deprecated. Use --view (or -v)!

+
+ +

What view engine should I use?

+ +

The Express Application Generator allows you to configure a number of popular view/templating engines, including EJS, Hbs, Pug (Jade), Twig, and Vash, although it chooses Jade by default if you don't specify a view option. Express itself can also support a large number of other templating languages out of the box.

+ +
+

Note: If you want to use a template engine that isn't supported by the generator then see Using template engines with Express (Express docs) and the documentation for your target view engine.

+
+ +

Generally speaking, you should select a templating engine that delivers all the functionality you need and allows you to be productive sooner — or in other words, in the same way that you choose any other component! Some of the things to consider when comparing template engines:

+ + + +
+

Tip: There are many resources on the Internet to help you compare the different options!

+
+ +

For this project, we'll use the Pug templating engine (this is the recently-renamed Jade engine), as this is one of the most popular Express/JavaScript templating languages and is supported out of the box by the generator.

+ +

What CSS stylesheet engine should I use?

+ +

The Express Application Generator allows you to create a project that is configured to use the most common CSS stylesheet engines: LESS, SASS, Compass, Stylus.

+ +
+

Note: CSS has some limitations that make certain tasks difficult. CSS stylesheet engines allow you to use more powerful syntax for defining your CSS and then compile the definition into plain-old CSS for browsers to use.

+
+ +

As with templating engines, you should use the stylesheet engine that will allow your team to be most productive. For this project, we'll use the ordinary CSS (the default) as our CSS requirements are not sufficiently complicated to justify using anything else.

+ +

What database should I use?

+ +

The generated code doesn't use/include any databases. Express apps can use any database mechanism supported by Node (Express itself doesn't define any specific additional behavior/requirements for database management).

+ +

We'll discuss how to integrate with a database in a later article.

+ +

Creating the project

+ +

Local Library 샘플 앱을 위해서 우리는 express-locallibrary-tutorial 라는 이름의 프로젝트를 생성할 것입니다. Pug 라는(jade의 후속격) 템플릿 라이브러리를 사용할 것이며, CSS stylesheet 엔진은 사용하지 않습니다.

+ +

First, navigate to where you want to create the project and then run the Express Application Generator in the command prompt as shown:

+ +
express express-locallibrary-tutorial --view=pug
+
+ +

The generator will create (and list) the project's files.

+ +
   create : express-locallibrary-tutorial\
+   create : express-locallibrary-tutorial\public\
+   create : express-locallibrary-tutorial\public\javascripts\
+   create : express-locallibrary-tutorial\public\images\
+   create : express-locallibrary-tutorial\public\stylesheets\
+   create : express-locallibrary-tutorial\public\stylesheets\style.css
+   create : express-locallibrary-tutorial\routes\
+   create : express-locallibrary-tutorial\routes\index.js
+   create : express-locallibrary-tutorial\routes\users.js
+   create : express-locallibrary-tutorial\views\
+   create : express-locallibrary-tutorial\views\error.pug
+   create : express-locallibrary-tutorial\views\index.pug
+   create : express-locallibrary-tutorial\views\layout.pug
+   create : express-locallibrary-tutorial\app.js
+   create : express-locallibrary-tutorial\package.json
+   create : express-locallibrary-tutorial\bin\
+   create : express-locallibrary-tutorial\bin\www
+
+   change directory:
+     > cd express-locallibrary-tutorial
+
+   install dependencies:
+     > npm install
+
+   run the app:
+     > SET DEBUG=express-locallibrary-tutorial:* & npm start
+ +

At the end of the output, the generator provides instructions on how you install the dependencies (as listed in the package.json file) and then how to run the application (the instructions above are for Windows; on Linux/macOS they will be slightly different).

+ +
+

Note: When using Windows, the && and & assumes you are using the Command Prompt. If you are using the new default PowerShell terminal do not concatenate the commands with && and &. Instead set the DEBUG environment variable with $ENV:DEBUG = "express-locallibrary-tutorial:*";. The npm start can be followed by the npm start. 

+
+ +

Running the skeleton website

+ +

At this point, we have a complete skeleton project. The website doesn't actually do very much yet, but it's worth running it to show how it works.

+ +
    +
  1. First, install the dependencies (the install command will fetch all the dependency packages listed in the project's package.json file). + +
    cd express-locallibrary-tutorial
    +npm install
    +
  2. +
  3. Then run the application. +
      +
    • On Windows, use this command: +
      SET DEBUG=express-locallibrary-tutorial:* & npm start
      +
    • +
    • On macOS or Linux, use this command: +
      DEBUG=express-locallibrary-tutorial:* npm start
      +
      +
    • +
    +
  4. +
  5. Then load http://localhost:3000/ in your browser to access the app.
  6. +
+ +

You should see a browser page that looks like this:

+ +

Browser for default Express app generator website

+ +

You have a working Express application, serving itself to localhost:3000.

+ +
+

Note: You could also start the app just using the npm start command. Specifying the DEBUG variable as shown enables console logging/debugging. For example, when you visit the above page you'll see debug output like this:

+ +
>SET DEBUG=express-locallibrary-tutorial:* & npm start
+
+> express-locallibrary-tutorial@0.0.0 start D:\github\mdn\test\exprgen\express-locallibrary-tutorial
+> node ./bin/www
+
+  express-locallibrary-tutorial:server Listening on port 3000 +0ms
+GET / 304 490.296 ms - -
+GET /stylesheets/style.css 200 4.886 ms - 111
+
+
+ +

Enable server restart on file changes

+ +

Any changes you make to your Express website are currently not visible until you restart the server. It quickly becomes very irritating to have to stop and restart your server every time you make a change, so it is worth taking the time to automate restarting the server when needed.

+ +

One of the easiest such tools for this purpose is nodemon. This is usually installed globally (as it is a "tool"), but here we'll install and use it locally as a developer dependency, so that any developers working with the project get it automatically when they install the application. Use the following command in the root directory for the skeleton project:

+ +
npm install --save-dev nodemon
+ +

If you still choose to install nodemon globally to your machine, and not only to your project's package.json file:

+ +
npm install -g nodemon
+ +

If you open your project's package.json file you'll now see a new section with this dependency:

+ +
 "devDependencies": {
+    "nodemon": "^1.18.10"
+}
+
+ +

Because the tool isn't installed globally we can't launch it from the command line (unless we add it to the path) but we can call it from an NPM script because NPM knows all about the installed packages. Find the the scripts section of your package.json. Initially, it will contain one line, which begins with "start". Update it by putting a comma at the end of that line, and adding the "devstart" line seen below:

+ +
  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www",
+    "serverstart": "DEBUG=express-locallibrary-tutorial:* npm run devstart"
+  },
+
+ +

We can now start the server in almost exactly the same way as previously, but with the devstart command specified:

+ + + +
+

Note: Now if you edit any file in the project the server will restart (or you can restart it by typing rs on the command prompt at any time). You will still need to reload the browser to refresh the page.

+ +

We now have to call "npm run <scriptname>" rather than just npm start, because "start" is actually an NPM command that is mapped to the named script. We could have replaced the command in the start script but we only want to use nodemon during development, so it makes sense to create a new script command.

+ +

The serverstart command added to the scripts in the package.json above is a very good example. Using this approach means you no longer have to type a long command shown to start the server. Note that the particular command added to the script works for macOS or Linux only.

+
+ +

The generated project

+ +

Let's now take a look at the project we just created.

+ +

Directory structure

+ +

The generated project, now that you have installed dependencies, has the following file structure (files are the items not prefixed with "/"). The package.json file defines the application dependencies and other information. It also defines a startup script that will call the application entry point, the JavaScript file /bin/www. This sets up some of the application error handling and then loads app.js to do the rest of the work. The app routes are stored in separate modules under the routes/ directory. The templates are stored under the /views directory.

+ +
/express-locallibrary-tutorial
+    app.js
+    /bin
+        www
+    package.json
+    package-lock.json
+    /node_modules
+        [about 6700 subdirectories and files]
+    /public
+        /images
+        /javascripts
+        /stylesheets
+            style.css
+    /routes
+        index.jsusers.js
+    /views
+        error.pug
+        index.puglayout.pug
+
+
+ +

The following sections describe the files in a little more detail.

+ +

package.json

+ +

The package.json file defines the application dependencies and other information:

+ +
{
+  "name": "express-locallibrary-tutorial",
+  "version": "0.0.0",
+  "private": true,
+  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www"
+  },
+  "dependencies": {
+    "cookie-parser": "~1.4.3",
+    "debug": "~2.6.9",
+    "express": "~4.16.0",
+    "http-errors": "~1.6.2",
+    "morgan": "~1.9.0",
+    "pug": "2.0.0-beta11"
+  },
+  "devDependencies": {
+    "nodemon": "^1.18.10"
+  }
+}
+
+ +

The dependencies include the express package and the package for our selected view engine (pug). In addition, we have the following packages that are useful in many web applications:

+ + + +

The scripts section defines a "start" script, which is what we are invoking when we call npm start to start the server. From the script definition, you can see that this actually starts the JavaScript file ./bin/www with node. It also defines a "devstart" script, which we invoke when calling npm run devstart instead. This starts the same ./bin/www file, but with nodemon rather than node.

+ +
  "scripts": {
+    "start": "node ./bin/www",
+    "devstart": "nodemon ./bin/www"
+  },
+
+ +

www file

+ +

The file /bin/www is the application entry point! The very first thing this does is require() the "real" application entry point (app.js, in the project root) that sets up and returns the express() application object.

+ +
#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var app = require('../app');
+
+ +
+

Note: require() is a global node function that is used to import modules into the current file. Here we specify app.js module using a relative path and omitting the optional (.js) file extension.

+
+ +

The remainder of the code in this file sets up a node HTTP server with app set to a specific port (defined in an environment variable or 3000 if the variable isn't defined), and starts listening and reporting server errors and connections. For now you don't really need to know anything else about the code (everything in this file is "boilerplate"), but feel free to review it if you're interested.

+ +

app.js

+ +

This file creates an express application object (named app, by convention), sets up the application with various settings and middleware, and then exports the app from the module. The code below shows just the parts of the file that create and export the app object:

+ +
var express = require('express');
+var app = express();
+...
+module.exports = app;
+
+ +

Back in the www entry point file above, it is this module.exports object that is supplied to the caller when this file is imported.

+ +

Let's work through the app.js file in detail. First, we import some useful node libraries into the file using require(), including http-errors, expressmorgan and cookie-parser that we previously downloaded for our application using NPM; and path, which is a core Node library for parsing file and directory paths.

+ +
var createError = require('http-errors');
+var express = require('express');
+var path = require('path');
+var cookieParser = require('cookie-parser');
+var logger = require('morgan');
+
+ +

Then we require() modules from our routes directory. These modules/files contain code for handling particular sets of related "routes" (URL paths). When we extend the skeleton application, for example to list all books in the library, we will add a new file for dealing with book-related routes.

+ +
var indexRouter = require('./routes/index');
+var usersRouter = require('./routes/users');
+
+ +
+

Note: At this point, we have just imported the module; we haven't actually used its routes yet (this happens just a little bit further down the file).

+
+ +

Next, we create the app object using our imported express module, and then use it to set up the view (template) engine. There are two parts to setting up the engine. First, we set the 'views' value to specify the folder where the templates will be stored (in this case the subfolder /views). Then we set the 'view engine' value to specify the template library (in this case "pug").

+ +
var app = express();
+
+// view engine setup
+app.set('views', path.join(__dirname, 'views'));
+app.set('view engine', 'pug');
+
+ +

The next set of functions call app.use() to add the middleware libraries into the request handling chain. In addition to the 3rd party libraries we imported previously, we use the express.static middleware to get Express to serve all the static files in the /public directory in the project root.

+ +
app.use(logger('dev'));
+app.use(express.json());
+app.use(express.urlencoded({ extended: false }));
+app.use(cookieParser());
+app.use(express.static(path.join(__dirname, 'public')));
+
+ +

Now that all the other middleware is set up, we add our (previously imported) route-handling code to the request handling chain. The imported code will define particular routes for the different parts of the site:

+ +
app.use('/', indexRouter);
+app.use('/users', usersRouter);
+
+ +
+

Note: The paths specified above ('/' and '/users') are treated as a prefix to routes defined in the imported files. So for example, if the imported users module defines a route for /profile, you would access that route at /users/profile. We'll talk more about routes in a later article.

+
+ +

The last middleware in the file adds handler methods for errors and HTTP 404 responses.

+ +
// catch 404 and forward to error handler
+app.use(function(req, res, next) {
+  next(createError(404));
+});
+
+// error handler
+app.use(function(err, req, res, next) {
+  // set locals, only providing error in development
+  res.locals.message = err.message;
+  res.locals.error = req.app.get('env') === 'development' ? err : {};
+
+  // render the error page
+  res.status(err.status || 500);
+  res.render('error');
+});
+
+ +

The Express application object (app) is now fully configured. The last step is to add it to the module exports (this is what allows it to be imported by /bin/www).

+ +
module.exports = app;
+ +

Routes

+ +

The route file /routes/users.js is shown below (route files share a similar structure, so we don't need to also show index.js). First, it loads the express module and uses it to get an express.Router object. Then it specifies a route on that object and lastly exports the router from the module (this is what allows the file to be imported into app.js).

+ +
var express = require('express');
+var router = express.Router();
+
+/* GET users listing. */
+router.get('/', function(req, res, next) {
+  res.send('respond with a resource');
+});
+
+module.exports = router;
+
+ +

The route defines a callback that will be invoked whenever an HTTP GET request with the correct pattern is detected. The matching pattern is the route specified when the module is imported ('/users') plus whatever is defined in this file ('/'). In other words, this route will be used when an URL of /users/ is received.

+ +
+

Tip: Try this out by running the server with node and visiting the URL in your browser: http://localhost:3000/users/. You should see a message: 'respond with a resource'.

+
+ +

One thing of interest above is that the callback function has the third argument 'next', and is hence a middleware function rather than a simple route callback. While the code doesn't currently use the next argument, it may be useful in the future if you want to add multiple route handlers to the '/' route path.

+ +

Views (templates)

+ +

The views (templates) are stored in the /views directory (as specified in app.js) and are given the file extension .pug. The method Response.render() is used to render a specified template along with the values of named variables passed in an object, and then send the result as a response. In the code below from /routes/index.js you can see how that route renders a response using the template "index" passing the template variable "title".

+ +
/* GET home page. */
+router.get('/', function(req, res, next) {
+  res.render('index', { title: 'Express' });
+});
+
+ +

The corresponding template for the above route is given below (index.pug). We'll talk more about the syntax later. All you need to know for now is that the title variable (with value 'Express') is inserted where specified in the template.

+ +
extends layout
+
+block content
+  h1= title
+  p Welcome to #{title}
+
+ +

Challenge yourself

+ +

Create a new route in /routes/users.js that will display the text "You're so cool" at URL /users/cool/. Test it by running the server and visiting http://localhost:3000/users/cool/ in your browser

+ + + +

Summary

+ +

You have now created a skeleton website project for the Local Library and verified that it runs using node. Most importantly, you also understand how the project is structured, so you have a good idea where we need to make changes to add routes and views for our local library.

+ +

Next, we'll start modifying the skeleton so that it works as a library website.

+ +

See also

+ + + +

{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}

+ +

In this module

+ + -- cgit v1.2.3-54-g00ecf