[转]Building a REST-Backend for Angular with Node.js & Express
本文转自:https://malcoded.com/posts/angular-backend-express
Angular is a single page application framework. Unfortunately, that does not mean that you don't require a server for certain tasks.
After all, your data has to be served from somewhere...
But don't worry, setting up a server is easier than you might think. In fact, the first server we will create does only consist of three lines of code! For that, we will be using Node.js that allows us to use JavaScript to write our server-applications. We will also use the Express framework to create your first REST-API in just a few, simple steps.
In this tutorial, we will take a look at creating server-applications with Node.js and the Express framework in relation to angular. We will not only create our first small server-application, but also create a functional REST-API to serve our data.
Afterward, we take a close look, how we can utilize our new API, to request and send data from any angular application.
Now you might ask yourself: "What the .... is a REST-API?"
Don't worry, we will come to that, as well!
Ready?
Let's get started!
REST is not what you are looking for?
Try GraphQL with Angular Apollo & Express instead!
Not a fan of Node.js backends?
Then this guide to building a REST-API with ASP.Core is for you!
Setting up a new Express Project
As angular developers, we are used to generating our project structure with the angular-cli. Unfortunately, there is no such thing as a node-cli. That means we have to create our project files by hand. Can you believe that?
Well, it is not that bad as it sounds. To create our first functional node.js server application, we only have to create one file.
That file is a simple JavaScript file. It is the entry point for our server application. These files are typically called index.js or server.js.
I like server.js, so let's go ahead and create that file in a new directory of your choice.
Done! Not that hard, was it?
Setting up the node.js Environment
To run a node.js application, we have to install node.js on our machine first. You can download it at theofficial node.js website. For this tutorial, it does not matter, which version you choose. If you want to be on the save side, choose the long-term-support version (LTS).
Download the setup-executable and follow the instructions to install node.js on your computer. At one point, the wizard will ask if you want to install npm, as well. Make sure you do so. On Windows machines, you may need to restart your computer afterward.
Now that we have everything installed, we can initialize a new npm-project. What this will do for us, is generate a new package.json file and fill in its basic structure. As an angular developer, you should be familiar with this file already. It is also included in your angular projects. It keeps track of all dependencies of your application.
Let's generate the package.json file, by opening a command line interface in your server-application's directory. Use the command
npm init
and answer the questions, the tool is asking you. It does not matter what you type in. It will have no effect on your application itself. It is just meta-data.
Creating our first Node.js Server-Application
In this tutorial, we are going to create a server using the Express framework. While it is certainly possible, to create a server application without any frameworks, it makes development much easier.
So, the first line of our application looks like this:
const express = require('express');
In this piece of code, we first create a constant called "express" that we will later use to set up the express framework.
What does require do?
Express is an external dependency. By using "require" we tell node.js that it has to be pulled into our code because we need it.
In angular, we are doing just the same very often. The only difference here is, that we use a little bit different syntax.
Because we are using Typescript in angular, we are used to import statements. In fact, these import statements are compiled to the require statements when the TypeScript is compiled to JavaScript.
The above line would look this in TypeScript:
import * as express from 'express'
Looks more familiar, doesn't it?
Installing External Dependencies
Just like in angular, external dependencies have to be pulled and installed, before they can be used. Installed dependencies are located in a directory called "node_modules" inside of the root directory.
To install external dependencies, we are using package-managers like npm.
Use the following command to install express using npm:
npm install express --save
This command should have created the "node_modules" folder inside of your project directory.
Initializing the Express Framework
To initialize the express framework, we need to call the constant express function we just required. It will return an Express-Object. This Express-Object is essential and used to set up the application itself, add routes and rest-endpoints initialize middleware.
Doing so looks like this:
const app = express();
Again, nothing fancy, right?
Starting our Server
Now that we have initialized the framework, we can fire up our server. This is done by calling the "listen"-method of our Express-Object. This method tells the server to listen for incoming requests on the given port.
app.listen(8000, () => {
console.log('Server started!');
});
In this case, we tell it to listen on port 8000. We also pass in a callback-function, that is called, once the server has successfully started. Inside there we log our successful start to the console.
Running our Server with Node.js
To run our script, we need to tell node.js to execute it. This can be done, using the node command in your command line interface.
Open a new command line interface in your project root directory and start your server by typing:
node server.js
Alternatively, you can also use
npm start
because npm has created a script inside of our package.json that is internally calling the node command.
If you are using Visual Studio Code, you can also start your server by hitting F5. This also automatically attaches the debugger to the process, which is quite useful.
"REST-API"? Can you eat that?
As I told you already, we are going to create a REST-API. But what is that exactly? Let's find out!
I will try to keep this short: REST is a standardized way of building http-endpoints.
It uses standard HTTP-verbs like get, post, put & delete to express read, create update & delete (CRUD) operations.
All these methods (verbs) are applied to one endpoint, which represents the object to be modified. This has an object-oriented touch to it,
For example, if I wanted to modify a cat in any way, the endpoint would be named "cats" or "cat", depending on who you ask. I prefer the plural form fro myself.
Here is how the CRUD operations are modeled.
CRUD Operations
Create: To create a new object under an endpoint, a post-request is sent to the REST-Endpoint containing the new object to create in the post-body.
Read: To read all objects from an endpoint, e.g if you want to know about all cats, a get-request is sent to the "cats" endpoint. If you are interested in one specific cat, you append the id/name of the cat to the route "cats/cat1".
Update: To update an object, a put request is sent to the endpoint. The identifier is added to the route e.g. "cat/cat1". The information of the object is added to the put-body.
Delete: To delete an object, a delete request is sent to the endpoint with the identifier of the wanted object added to the route.
These crud-operations can be directly mapped to the database, for example mongodb, if you are using the MEAN-stack.
Our first REST-Endpoint
Enough theory for now, let's dive right into the code. For our example, we are going to create a cat-endpoint, possibly serving a database of all cats in the world. Yes, all of them!
Getting all Objects from an Endpoint
As discussed before, we get a list of all objects of an endpoint, by sending a get request to that endpoint directly.
Now, we have to tell our server, what to do, if it receives a request at that endpoint.
To do so, we are defining a so-called route, which is the "path" to the endpoint. In this example, the base path to our REST-API will be "api". This enables us to serve other things next to the REST-API. For example, we could serve our angular application under the "app" route.
To define a route, we call the route-method on our express object.
Next, we wall the get-method on that route, to tell express that we want to register a callback for the HTTP-get request at that specific route.
app.route('/api/cats').get((req, res) => {
});
Inside of this callback method, we can decide, what should happen, when a user requests that route. For that, we get two objects. The request-object and the response-object.
The request-object does contain details about the request of the user. With this object, we get access to all the data of the request, for example, the headers or the body.
The response-object on the other hand helps us to send a response back. It does not only contain all the information of the response but also convenient methods, we can use to shape our response.
In our example, we are going to use the send-method, to send back any JavaScript object as JSON in the response body.
app.route('/api/cats').get((req, res) => {
res.send({
cats: [{ name: 'lilly' }, { name: 'lucy' }]
});
});
Getting one specific Object from an Endpoint
The second method of a REST-endpoint, is getting one specific element from the API. By convention, the identifier of that object is appended to the route.
For example, if we want to get everything about the cat called "lucy", we would call the following route:
api/cats/lucy
But now we got a problem. The last of the element of the route is completely dynamic, as it could be any cat's name. So how do we tell express that we want to handle that route?
For that, express has a concept called route parameter and it works surprisingly similar to angular route parameters. We declare a parameter by using a colon.
The code to set this route up looks like this:
app.route('/api/cats/:name').get((req, res) => {});
The ":name" tells express, that we expect a dynamic string as input. We can get the value of this route-parameter by getting the params-object from the request object. We query it using the name of our route-parameter ("name").
app.route('/api/cats/:name').get((req, res) => {
const requestedCatName = req.params['name']
});
All we have to do now is to return the cat with that name. In a real-world application, we would now search our database for that cat. But for demonstration purposes, we just return a new cat-object with the requested name.
app.route('/api/cats/:name').get((req, res) => {
const requestedCatName = req.params['name'];
res.send({ name: requestedCatName });
});
Sending a new Object to an Endpoint
Another method of a REST-API is creating a new object at the endpoint. This method is different to the methods we looked at before because it is using the HTTP-post-request instead of the get-request.
This REST-method is used to send new objects to the server. For example, if we would want to insert a new cat into our (not existing) cat-database, we would use this method for that.
To get access to the post-body of the request, we need to add a little tool called body-parser. This parses the body of the requests and adds it as a new property to the request object.
We need the body of the post request, because it contains the information about the new cat we are about to create.
Just add the body-parser to the dependencies of our server by using this command:
npm install body-parser --save
We then require it and tell express to use it for every request (more on that later).
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.route('/api/cats').post((req, res) => {
res.send(201, req.body);
});
You may have noticed that something else looks different here. We are using the "send"-method with two parameters instead of one. Now, the first parameter is the HTTP-status-code and the second one our payload. Normally, the "send"-method uses the status code "200" - OK. Because the request "created" something, a new cat entry in our database, for example, the status code "201" - Created is a much better fit.
Changing an Object at an Endpoint
Inserting new Objects might not cover all of your needs. Depending on your use-case, you probably want to modify existing objects. We can create a route that allows for that using the express-put-method.
app.route('/api/cats/:name').put((req, res) => {
res.send(200, req.body);
});
Deleting an Object at an Endpoint
Creating a delete method is quite simple. All we have to do is the delete-method from express. Again, we are using a route-parameter, to determine which cat to delete from the database.
app.route('/api/cats/:name').delete((req, res) => {
res.sendStatus(204);
});
The status-code "204" -No Content, means that we are not sending back any payload, but the request was successful.
Plug & Play Functionality using Express-Middleware
That's almost it. We have successfully created a REST-API!
Before we continue, by building the corresponding angular application, we should take a short look at middleware in express, because it is such an important concept of the framework.
It will also help as to prevent a very common mistake.
So what is Middleware?
Middleware is a very broad and abstract concept. Basically, it is software, that is placed between two other components. Well, I told you it is abstract...
What does that mean for our application?
Everything in express is middleware. There is some component that takes the incoming requests and there is something that spits out the responses. Everything in between is handled by middleware.
Middleware in Express
Our routes with their callbacks, for example, are a kind of middleware. We get a request and help to shape a response from that.
It turns out, the body-parser we used already, is middleware as well. It intercepts every request and looks for their bodies. It then modifies the request object to contain that body information.
Middleware in express builds a kind of chain. The request is passed from the first registered middleware to the last one. Once there is no one left that wants to intercept the request, the response is sent back.
Enabling CORS
The first thing I realize, when I want to test my brand new API with my angular app, is, that I forgot to enable CORS.
CORS or cross-origin-resource sharing is the process of making an HTTP-request to a top-level domain that is different to the domain, the browser is currently at. For example, if I would make a request from this page to google.com, it would be a cross-origin-request.
This same-origin-policy prevents us from making HTTP-requests from our JavaScript code to APIs, that don't want to be called from a different origin. And that makes absolute sense. I don't want my API to be used by other sites, possibly doing malicious things with the gathered data.
When it comes to single-page-applications (like angular) though, almost every HTTP-request is made from JavaScript (AJAX). Furthermore is not to uncommon, that the API is not hosted under the same domain as the angular app.
We then have to enable CORS. But it is not just an on/off feature. We can enable COR only from certain domains.
We can do so with express by using the CORS middleware.
npm install cors --save
const cors = require('cors')
var corsOptions = {
origin: 'http://example.com',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions))
This middleware will now intercept every request and add the corresponding cors headers to the response.
Consuming our Express-API in an Angular Application
Now I will show you real quick, how to integrate your API into your angular application.
For that, I assume that you know how to set up a basic application using the angular-cli. Some basic understanding could help, as well.
If you feel like you are lacking knowledge in one or both of the mentioned things, I recommend you read my Angular Beginners Guidefirst.
So first we create a basic angular-cli application. Of course, you can do this with any existing application, as well. All we are going to do here is to create an angular service, that consumes our new REST-API.
For that, we are using the angular HttpClient. So you need to import the HttpClientModule into a moduleof your choice, but typically the App-Module.
Next, create a new service. I will call that one "CatService".
Here is what this service looks like:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
export interface Cat {
name: string;
}
@Injectable()
export class CatService {
constructor(private http: HttpClient) {}
getAllCats(): Observable<Cat[]> {
return this.http.get<Cat[]>('http://localhost:8000/api/cats');
}
getCat(name: string): Observable<Cat> {
return this.http.get<Cat>('http://localhost:8000/api/cats/' + name);
}
insertCat(cat: Cat): Observable<Cat> {
return this.http.post<Cat>('http://localhost:8000/api/cats/', cat);
}
updateCat(cat: Cat): Observable<void> {
return this.http.put<void>('http://localhost:8000/api/cats/' + cat.name, cat);
}
deleteCat(name: string) {
return this.http.delete('http://localhost:8000/api/cats/' + name);
}
}
Conclusion
In this tutorial, we learned how to set up a node.js server-application from scratch and created a very basic but functional REST-API using the express framework.
I hope you enjoyed this post.
If you did please hit the share buttons below and help other people building their APIs, as well.
Have a fantastic day!
[转]Building a REST-Backend for Angular with Node.js & Express的更多相关文章
- Practical Node.js (2018版) 第8章:Building Node.js REST API Servers
Building Node.js REST API Servers with Express.js and Hapi Modern-day web developers use an architec ...
- 深入理解jQuery、Angular、node中的Promise
最初遇到Promise是在jQuery中,在jQuery1.5版本中引入了Deferred Object,这个异步队列模块用于实现异步任务和回调函数的解耦.为ajax模块.队列模块.ready事件提供 ...
- socket.io+angular.js+express.js做个聊天应用(四)
接着上一篇 使用angularjs构建聊天室的client <!doctype html> <html ng-app="justChatting"> < ...
- soket.io.js + angular.js + express.js(node.js)
soket.io.js + angular.js + express.js(node.js) 今天搭建个soket.io.js + angular.js + express.js的环境, 采坑无数,特 ...
- Angular和Vue.js 深度对比
Vue.js 是开源的 JavaScript 框架,能够帮助开发者构建出美观的 Web 界面.当和其它网络工具配合使用时,Vue.js 的优秀功能会得到大大加强.如今,已有许多开发人员开始使用 Vue ...
- EmberJS 为什么我偏爱 Ember.js 胜过 Angular 和 React.js
文章写的很老到,非常值得一看!评论也很精彩,值得一看 为什么我偏爱 Ember.js 胜过 Angular 和 React.js 前几天看到了这篇文章:Why I prefer Ember.js ov ...
- Angular、React.js 和Node.js到底选谁?
为了工作,程序员选择正确的框架和库来构建应用程序是至关重要的,这也就是为什么Angular和React之间有着太多的争议.Node.js的出现,让这场战争变得更加复杂,虽然有选择权通常是一件很棒的事情 ...
- socket.io+angular.js+express.js做个聊天应用(三)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/www19940501a/article/details/27590611 接着前面博客文章socke ...
- Angular build Error:In this configuration Angular requires Zone.js
Angular cli 运行 build后打开生成的index.html报错:In this configuration Angular requires Zone.js 生成代码如下: ng bui ...
随机推荐
- SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase] 错误
在一次改bug的过程,爆出了数据库错误,但是一看后面控制台,并没有爆出以前的具体的数据库错误的原因,而是 SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, In ...
- 用python语言算π值并且带有进度条
用python算圆周率π 1.准备第三方库pip 打开cmd 输入代码:pip install requests ,随后就会成功 因为小编已经安装好了,所以就不把图截出来了 2.利用马青公式求π ...
- pb数据导出
pb数据导出(一) 1.在窗口新建用户事件 ue_export 2.事件调用函数 gf_dw_to_excel(THIS.dw_dict) 3.写函数 :boolean lb_setborde ...
- PB9.0连接sqlserver2008 R2
pb9不支持sql2000以上版本的数据库直连.因此要连接2000以上的版本必须用odbc. windows下的odbc管理器打开方式:窗体键+R 调出运行对话框 输入 odbcad32 确定弹出od ...
- 为什么需要micro-service构建平台
最近一直在做micro-service的开发平台建设.由于这是一个实验项目,目前所有工作都得靠自己操刀. 今天在总结用python开发一个web service时,偶有所得,这让我建设micro-se ...
- 2018/7/26号碰到了个奇怪的问题(http有问题,但是ftp没毛病)
过程大概是这样的 本来测试服务器中发ajax没问题,突然暴毙了,服务器又通过ajax发了另外一个请求(与之前不一样). nginx reload 没毛病 ,ftp 也使用正常. 出了什么问题呢? ...
- Ngon 是啥
https://www.gamefromscratch.com/post/2011/07/11/So-whats-an-ngon-anyways.aspx 在 blender 里面 Add 一个 Cy ...
- Javascript高级编程学习笔记(2)—— Script标签
script标签 js在浏览器中的使用,肯定会涉及到script标签. 那么script标签有哪些属性呢? 1.async:异步加载(不让页面等待该脚本的加载执行,异步加载页面的其他部分) 2.cha ...
- Hibernate入门1 - Hibernate概述及第一个小例子
一.什么是ORM? ORM,即Object Relational Mapping.我们知道,利用面向对象的思想编写的数据库应用程序最终都是把对象信息保存在关系型数据库中,于是需要编写与底层数据库相关的 ...
- Java面试集合(一)
前言 大家好,给大家带来Java面试集合(一)的概述,希望你们喜欢 一 1.Java按应用范围可划分几个版本? 答:Java按应用范围有三个版本,分别是JavaSE,JavaEE,JavaME. 2. ...