angular8 rest
by Bruno Krebs
布鲁诺·克雷布斯(Bruno Krebs)
In this post I’ll show you how you can quickly build a serverless full stack app with static file hosting, a secure REST API, and a robust persistence layer.
在本文中,我将向您展示如何使用静态文件托管,安全的REST API和可靠的持久层快速构建无服务器的全栈应用程序。
Here’s how we’ll manage all the moving parts:
这是我们如何管理所有活动部件的方法:
Identity management and security supported by Auth0 and JSON Web Tokens (JWT)
Auth0和JSON Web令牌(JWT)支持的身份管理和安全性
Persistence layer with a MongoDB database hosted by mLab
具有由mLab托管的MongoDB数据库的 持久层
Static file hosting via deployment to GitHub Pages
通过部署到GitHub Pages的 静态文件托管
Since this app is quite simple in terms of features, it won’t be necessary to run MongoDB in your local environment. We’ll use mLab during development as well as in production. The only tools that you’ll need to install are NodeJS and NPM.
由于该应用程序的功能非常简单,因此无需在本地环境中运行MongoDB。 我们将在开发和生产中使用mLab。 您需要安装的唯一工具是NodeJS和NPM 。
Our application will have the following features:
我们的应用程序将具有以下功能:
We are going to create our new Angular app with Angular CLI. Actually, we will be using this tool during the whole process to create components/services and build our app for production.
我们将使用Angular CLI创建新的Angular应用程序。 实际上,我们将在整个过程中使用此工具来创建组件/服务并构建用于生产的应用程序。
Here is a list of a few commands that we will have to issue to install Angular CLI and to create our app skeleton:
以下列出了一些命令,我们将在安装Angular CLI和创建应用程序框架时发出这些命令:
# install Angular CLI globally
npm install -g @angular/cli
# create skeleton
ng new task-list && cd task-list
# serve the skeleton on our dev env
ng serve
The last command is responsible for packaging our application with the development profile, and for serving it locally with Webpack Development Server. After executing all these commands, navigate to http://localhost:4200/
to see it up and running.
最后一个命令负责将我们的应用程序与开发配置文件打包在一起,并通过Webpack Development Server在本地提供服务 。 执行完所有这些命令后,导航至http://localhost:4200/
以查看其运行情况。
The first thing that we are going to take care of in our application is security. Security must be a first priority in any application that handles sensitive, third party data like the task list that we are about to develop.
我们在应用程序中要注意的第一件事是安全性。 在处理敏感的第三方数据(例如我们将要开发的任务列表)的任何应用程序中,安全性必须是第一要务。
To start, sign up for a free Auth0 account and take note of Client ID
and Domain
. Both values are going to be used to configure Lock: an embeddable login system.
首先, 注册一个免费的Auth0帐户,并记下Client ID
和Domain
。 这两个值都将用于配置Lock :可嵌入的登录系统。
Important: Auth0 requires a list of Allowed Callback URLs. This list contains all the URLs to which Auth0 can redirect a user to after issuing a JWT. Therefore we must configure at least two URLs: http://localhost:4200/
and the URL where our app will be exposed, something like: https://brunokrebs.github.io/task-list/
. This URL will be defined when we release to GitHub Pages.
重要提示 :Auth0需要允许的回调URL列表。 此列表包含在发出JWT之后Auth0可以将用户重定向到的所有URL。 因此,我们必须至少配置两个URL: http://localhost:4200/
以及将公开我们的应用程序的URL,例如: https://brunokrebs.github.io/task-list/
: https://brunokrebs.github.io/task-list/
。 当我们发布到GitHub Pages时,将定义此URL。
To use Lock, we must install two libraries in our application: auth0-lock
and angular2-jwt
. Since we are using TypeScript with Angular, we will also install the @types/auth0-lock
library, which provides TypeScript definitions for Lock. Also, since we want to provide our users a good looking interface, we are going to install Angular Material. These dependencies are installed with the following commands:
要使用Lock,我们必须在应用程序中安装两个库: auth0-lock
和angular2-jwt
。 由于我们在Angular中使用TypeScript,因此我们还将安装@types/auth0-lock
库,该库提供Lock的TypeScript定义。 另外,由于我们希望为用户提供美观的界面,因此我们将安装Angular Material 。 这些依赖项通过以下命令安装:
# Auth0 Lock and Angular 2 JWT runtime deps
npm install --save auth0-lock angular2-jwt @angular/material
# Types definitions for Auth0 Lock
npm install --save-dev @types/auth0-lock
Let’s use Angular CLI to create a NavBarComponent
. This component will have Sign in and Sign out buttons. We will also create a AuthService
that will be responsible for sign in
, sign out
and to validate if the user is authenticated
or not.
让我们使用Angular CLI创建一个NavBarComponent
。 该组件将具有“ 登录”和“ 退出”按钮。 我们还将创建一个AuthService
,该服务将负责sign in
, sign out
并验证用户是否通过authenticated
。
# generates NavBarComponent files under src/app/nav-bar
ng g component nav-bar
# generates AuthService under src/app/auth.service.ts
ng g service auth
After executing these commands, Angular CLI will have created the following file structure:
执行完这些命令后,Angular CLI将创建以下文件结构:
src
|-app
|-nav-bar
|-nav-bar.component.ts
|-nav-bar.component.html
|-nav-bar.component.css
|-auth.service.ts
Actually two extra files were created:
src/app/auth.service.spec.ts
andsrc/app/nav-bar/nav-bar.component.spec.ts
. We would use these files to write tests for both the component and the service. However, for the sake of simplicity, we won't address testing in this post. You can check the following references to read about testing in Angular: Angular 2 Testing In Depth: Services; Angular Testing; Testing Components in Angular 2 with Jasmine实际上创建了两个额外的文件:
src/app/auth.service.spec.ts
和src/app/nav-bar/nav-bar.component.spec.ts
。 我们将使用这些文件为组件和服务编写测试。 但是,为了简单起见,本文中不涉及测试。 您可以查看以下参考资料,以了解有关Angular中的测试的信息: Angular 2深度测试:服务 ; 角度测试 ; 使用Jasmine测试Angular 2中的组件
To integrate with Lock, let’s first implement src/app/auth.service.ts
with the following code:
为了与Lock集成,我们首先使用以下代码实现src/app/auth.service.ts
:
In the code above, there are three things that worth mentioning. First, we must replace AUTH0_CLIENT_ID
and AUTH0_DOMAIN
with the values that we noted previously. Second, the ID_TOKEN
references the key were the JWT will be saved (on the user's browser localStorage
). And third, the constructor of this service adds a callback listener to the authenticated
event on Lock. This callback saves the token issued by Auth0 in localStorage
. To sign out a user, it is just a matter of removing this token from localStorage
.
在上面的代码中,有三件事值得一提。 首先,我们必须将AUTH0_CLIENT_ID
和AUTH0_DOMAIN
替换为我们先前AUTH0_DOMAIN
下的值。 其次, ID_TOKEN
引用将保存JWT的密钥(在用户的浏览器localStorage
)。 第三,此服务的构造函数将回调侦听器添加到Lock上已通过authenticated
事件。 此回调将Auth0发出的令牌保存在localStorage
。 要注销用户,只需从localStorage
删除此令牌即可。
Our AuthService
class is good to go, but unlike components
, Angular CLI does not add services
to our @NgModule
definition by default. To do this, open the src/app/app.module.ts
file, add this service
as a provider
and add Angular Material in the imports
array:
我们的AuthService
类很好用,但是与components
不同,Angular CLI默认不会将services
添加到我们的@NgModule
定义中。 为此,请打开src/app/app.module.ts
文件,将此service
添加为provider
并在imports
数组中添加Angular Material:
We can now focus on implementing our NavBarComponent
. First, we will inject AuthService
and add three public methods that will be used by our HTML interface. Then we will implement the interface and add some CSS rules to improve it.
现在,我们可以集中精力实现NavBarComponent
。 首先,我们将注入AuthService
并添加三个将由我们HTML接口使用的公共方法。 然后,我们将实现该接口并添加一些CSS规则以对其进行改进。
Let’s open the src/app/nav-bar/nav-bar.component.ts
file and implement the following code:
让我们打开src/app/nav-bar/nav-bar.component.ts
文件并实现以下代码:
This component simply gets AuthService
injected and nothing else. Injecting a service like this allows the user interface to call its methods, as we will see. Now, let's open src/app/nav-bar/nav-bar.component.html
and implement it as follows:
该组件只是注入了AuthService
,仅此而已。 如我们将看到的那样,注入这样的服务将允许用户界面调用其方法。 现在,让我们打开src/app/nav-bar/nav-bar.component.html
并实现它,如下所示:
Our NavBar
exposes our application's title along with two buttons. At any given time, only one button is truly visible to the user. The Sign In button is going to be visible when the user is not yet authenticated
and the Sign Out will be visible otherwise. To make our interface look better, we have also added a span.fill-space
element. This element will be responsible to push both buttons to the right border. To accomplish this, we need to add the CSS rule that follows to the src/app/nav-bar/nav-bar.component.css
file:
我们的NavBar
公开了我们应用程序的标题以及两个按钮。 在任何给定时间,用户只能真正看到一个按钮。 登录按钮将是可见的,当用户还没有通过authenticated
和登录输出将是可见的,否则。 为了使我们的界面看起来更好,我们还添加了span.fill-space
元素。 此元素将负责将两个按钮都推到右侧边框。 为此,我们需要在src/app/nav-bar/nav-bar.component.css
文件中添加以下CSS规则:
Good, we now have both the NavBarComponent
and the AuthService
fully implemented and integrated. But we still need to add this component to our src/app/app.component.html
file, otherwise it will never get rendered. To do this, just replace the content of this file with the following line of code:
好的,我们现在已经完全实现并集成了NavBarComponent
和AuthService
。 但是我们仍然需要将此组件添加到src/app/app.component.html
文件中,否则它将永远无法呈现。 为此,只需用以下代码行替换此文件的内容:
If we run our application now, it wouldn’t look neat because most major browsers come with an 8px
margin on body
elements and because we haven't configured any Angular Material Theme. We will fix both issues by updating our src/styles.css
file to look like:
如果我们现在运行我们的应用程序,它将看起来并不整洁,因为大多数主流浏览器的body
元素都带有8px
空白,并且我们还没有配置任何Angular Material Theme 。 我们将通过更新src/styles.css
文件来解决这两个问题:
We are now good to go, so let’s start our development server, by issuing ng serve
, and head to http://localhost:4200
to look how things are. You can even sign in and sign out, although there won't be much to see.
现在一切顺利,所以让我们启动我们的开发服务器,方法是发出ng serve
,然后转到http://localhost:4200
查看情况。 您甚至可以登录并注销 ,尽管没有什么可看的。
To make our application a friendly place, let’s add a welcoming message. To do that, first we will add two methods and inject AuthService
in the src/app/app.component.ts
file, making it look like this:
为了使我们的应用程序成为一个友好的地方,让我们添加欢迎消息。 为此,首先,我们将添加两个方法并将AuthService
注入src/app/app.component.ts
文件,使其如下所示:
After that we are going to add the message, as a md-card
component from Angular Material, to src/app/app.component.html
:
之后,我们将消息(作为Angular Material中的md-card
组件)添加到src/app/app.component.html
:
And last, we are going to make a fix to the interface by adding a rule to src/app/app.component.css
:
最后,我们将通过向src/app/app.component.css
添加一条规则来修复该接口:
Heading to our app, http://localhost:4200/
, we can see our new welcome message (if we are not authenticated).
前往我们的应用程序http://localhost:4200/
,我们可以看到新的欢迎消息(如果未通过身份验证)。
Now that we have our application integrated with Auth0, which allows our users to sign in and sign out, let’s create our serverless REST API. This API will handle POST
requests (to persist new tasks), GET
requests (to retrieve tasks from a user) and DELETE
requests (to remove tasks).
现在,我们已将应用程序与Auth0集成在一起,允许我们的用户登录和注销,让我们创建无服务器REST API。 该API将处理POST
请求(以保留新任务), GET
请求(以从用户检索任务)和DELETE
请求(以删除任务)。
We will first create a file called tasks.js
in a new folder called webtask
, and then we will add the following code to it:
我们将首先创建一个名为tasks.js
在一个名为新文件夹webtask
,然后我们将下面的代码添加到它:
The code is quite simple and easy to understand, but an overall explanation might come in handy. The main purpose of this file is to export an Express app that handles three HTTP methods for a single route, the main /
route. These three methods, as explained before, allow users to create, retrieve and delete tasks from collections on a MongoDB database.
该代码非常简单且易于理解,但是可能需要进行全面的解释。 该文件的主要目的是导出一个Express应用程序 ,该应用程序可为一条路由(主/
路由)处理三种HTTP方法。 如前所述,这三种方法允许用户在MongoDB数据库上的集合中创建,检索和删除任务。
Every user will have their own collection — not the best approach, since MongoDB can handle a maximum of 24,000 collections, but good enough to start. This collection is based on the sub
claim, which identifies user, present in the JWT issued by Auth0.
每个用户都有自己的集合-这不是最佳方法,因为MongoDB最多可以处理24,000个集合 ,但足以启动。 这个集合是基于所述sub
权利要求, 其识别用户 ,存在于JWT颁发Auth0。
The last function definition in the tasks.js
file, loadUserCollection
, is actually responsible for two things: security and MongoDB connection. When a user issues any request to our API, the function verifies if the authorization
header sent was actually signed by Auth0. If none is sent, a non-user-friendly error is generated. This is done through the jwt.verify
function with the help if AUTH0_SECRET
key. The second responsibility, connecting to MongoDB, is handled by the mongojs
module and depends on three configuration variables: MONGO_USER
, MONGO_PASSWORD
, MONGO_URL
.
tasks.js
文件中的最后一个函数定义loadUserCollection
实际上负责两件事:安全性和MongoDB连接。 当用户向我们的API发出任何请求时,该函数会验证发送的authorization
标头是否实际上是由Auth0签名的。 如果未发送任何消息,则会生成非用户友好的错误。 这是通过jwt.verify
函数以及AUTH0_SECRET
键的帮助来完成的。 连接到MongoDB的第二个责任由mongojs
模块处理,并取决于三个配置变量: MONGO_USER
, MONGO_PASSWORD
和MONGO_URL
。
All these configuration variables — three to connect to MongoDB and one to verify Auth0 tokens — are passed to Webtask when creating the serverless function. We will see how this is done soon.
创建无服务器功能时,所有这些配置变量(三个用于连接MongoDB,一个用于验证Auth0令牌)将传递给Webtask。 我们将很快看到这是如何完成的。
This is the whole REST API implementation, with this code we are ready to handle users requests that will be sent by the components that we are about to create on our Angular app. But there are a few more steps that we need to perform.
这是整个REST API的实现 ,有了这些代码,我们就可以处理将由我们将在Angular应用程序上创建的组件发送的用户请求。 但是,我们还需要执行一些其他步骤。
To make our lives easier and to avoid heaving to install and support MongoDB by ourselves, we are going to use mLab, a cloud-hosted MongoDB. The first thing that we have to do is to head to their website and sign up for a free account. After verifying our email address, we have to create a new deployment. Since we are just starting our app and we won’t get too much traffic, let’s choose the Single Node plan and the Sandbox type, which provides us 500 MB of DB storage for free. You will also need to type a database name, choose something like task-list
.
为了使我们的生活更轻松并避免自己安装和支持MongoDB,我们将使用云托管的MongoDB mLab 。 我们要做的第一件事是前往他们的网站并注册一个免费帐户。 确认电子邮件地址后,我们必须创建一个新的部署 。 由于我们只是启动我们的应用程序,并且不会收到太多流量,因此,我们选择“ 单节点”计划和“ 沙盒”类型,可免费为我们提供500 MB的数据库存储空间。 您还需要输入数据库名称,选择类似于task-list
。
The last thing that we will have to do is to create a user to connect to this database. If you choose task-list
as the name of your database, this is the link to create users.
我们要做的最后一件事是创建一个用户以连接到该数据库。 如果您选择task-list
作为数据库名称,则这是创建用户的链接 。
We will also need to create a Webtask account, but this as easy as it can be. Webtask, being a product of Auth0, relies on Lock and enables us to create an account with one of the following identity providers (IdP): Facebook, GitHub, Google or Microsoft. It is just a matter of hitting a button to create an account.
我们还需要创建一个Webtask帐户 ,但这很容易。 作为Auth0的产品,Webtask依靠Lock并允许我们使用以下身份提供者(IdP)之一创建帐户:Facebook,GitHub,Google或Microsoft。 只需单击一个按钮即可创建帐户。
After choosing an IdP, we are presented with a succinct, three-step process demonstrating how to create a Hello World serverless function. We already have a Webtask to deploy, so let’s follow only the first two steps in order to configure the CLI tool in our computer:
选择IdP之后,我们将进行一个简洁的三步过程,演示如何创建Hello World无服务器功能。 我们已经有一个Web任务要部署,因此让我们仅遵循前两个步骤即可在计算机中配置CLI工具:
# install Webtask CLI tool
npm install wt-cli -g
# initialize it with our email address
wt init me@somewhere.com
You will be asked to enter the verification code that was sent to your email address. This is the final step in the Webtask account configuration.
系统将要求您输入发送到您的电子邮件地址的验证码。 这是Webtask帐户配置的最后一步。
With mLab and Webtask accounts created and having Webtask CLI tool correctly configured, we can now deploy our serverless REST API to production. This is done with the following code:
创建了mLab和Webtask帐户并正确配置了Webtask CLI工具之后,我们现在可以将无服务器REST API部署到生产中了。 这是通过以下代码完成的:
wt create webtask/tasks.js \
--meta wt-compiler=webtask-tools/express \
-s AUTH0_SECRET=secret-from-auth0.com \
-s MONGO_USER=task-list-user \
-s MONGO_PASSWORD=111222 \
-s MONGO_URL=ds147069.mlab.com:47069/task-list \
--prod
The first option passed to the wt
tool specifies that we want to create
a Webtask based on our webtask/tasks.js
file. The second parameter identifies our code as being an Express app, which needs to be pre-compiled by Webtask with the help of webtask-tools/express
tool. The following four parameters are the secrets
that we use in our Webtask (-s
prefix denotes them as secrets
). The last parameter creates our Webtask in production
mode, which makes it faster.
传递给wt
工具的第一个选项指定我们要基于我们的webtask/tasks.js
文件create
一个Webtask。 第二个参数将我们的代码标识为Express应用程序,它需要由Webtask在webtask-tools/express
工具的帮助下进行预编译。 以下四个参数是我们在Webtask中使用的secrets
( -s
前缀表示它们为secrets
)。 最后一个参数在production
模式下创建我们的Webtask,从而使其速度更快。
Be aware that the values above have to be replaced with values that come from our Auth0 account and from our mLab account. AUTH0_SECRET
value can be found at the same place of Client ID
and Domain
. And the last three values, related to MongoDB, can be found at mLab's dashboard.
请注意,以上值必须替换为来自我们的Auth0帐户和mLab帐户的值。 可以在“ Client ID
和“ Domain
的同一位置找到AUTH0_SECRET
值。 与MongoDB相关的最后三个值可以在mLab的仪表板上找到。
Having successfully issued the Webtask creation command, we can now focus on working on the main feature of our Angular application, the task list component.
成功发出Webtask创建命令后,我们现在可以集中精力研究Angular应用程序的主要功能,即任务列表组件。
There are two components that we will need to create to allow users to interact with their task lists. We will create a TaskListComponent
, to expose the task list, and a TaskFormComponent
, that will allow the user to create new tasks. Besides these components, we will create a TaskListService
that will handle all AJAX requests. We will use Angular CLI to create them to us:
我们将需要创建两个组件,以允许用户与其任务列表进行交互。 我们将创建一个TaskListComponent
,以显示任务列表,以及一个TaskFormComponent
,以允许用户创建新任务。 除了这些组件之外,我们还将创建一个TaskListService
来处理所有AJAX请求。 我们将使用Angular CLI为我们创建它们:
# creates the main component that lists tasks
ng g component task-list
# creates a component to hold a form to add tasks
ng g component task-list/task-form
# creates a service to handle all interaction with our REST API
ng g service task-list/task-list
Both TaskListComponent
and TaskFormComponent
will depend on TaskListService
to communicate with our serverless REST API, so let's handle the service implementation first.
TaskListComponent
和TaskFormComponent
都将依赖TaskListService
与我们的无服务器REST API通信,因此让我们首先处理服务实现。
Open the recently created service file, src/app/task-list/task-list.service.ts
, and insert the following code:
打开最近创建的服务文件src/app/task-list/task-list.service.ts
,然后插入以下代码:
There are three important things to note in this code. First, the TASKS_ENDPOINT
constant. This constant must reference the URL returned by the wt create
command above.
此代码中有三点要注意。 首先, TASKS_ENDPOINT
常量。 该常量必须引用上面wt create
命令返回的URL 。
Second, this class is not using Http
from @angular/http
. It is using AuthHttp
, which is provided by angular2-jwt
and which integrates gracefully with auth0-lock
. Instances of this class automatically send an authorization
header with whatever content it finds on id_token
key on the user browser localStorage
. As you may have noted, this is the same place where we stored tokens when configuring AuthService
.
第二,这个类是不使用Http
从@angular/http
。 它使用的是AuthHttp
,它由angular2-jwt
提供,并与auth0-lock
完美集成。 此类的实例会自动发送一个authorization
标头,其中包含它在用户浏览器localStorage
id_token
密钥上找到的任何内容。 您可能已经注意到,这是我们在配置AuthService
时存储令牌的AuthService
。
Third, all methods in TaskListService
return Observables
, leaving the caller to decide what to do with the response sent by our serverless REST API.
第三, TaskListService
所有方法都返回Observables
,让调用者决定如何处理我们的无服务器REST API发送的响应。
To inject TaskListService
in our components, we need to make a few changes in our main @NgModule
, located in src/app/app.module.ts
:
要将TaskListService
注入我们的组件中,我们需要对主@NgModule
进行一些更改,位于src/app/app.module.ts
:
The first change that we made to our module was to add TaskListService
as a provider, just like we did before with AuthService
. The second change also added a provider, but in a more complex form.
我们对模块所做的第一个更改是将TaskListService
添加为提供程序,就像我们之前使用AuthService
。 第二个更改还添加了一个提供程序,但形式更为复杂。
The AuthHttp
provider needed help from a factory - declared as authHttpFactory
- to be created. This factory has Http
and RequestOptions
as dependencies, so we needed to define the provider as a literal object, passing this dependencies explicitly.
AuthHttp
提供程序需要工厂的帮助-被声明为authHttpFactory
才能创建。 该工厂将Http
和RequestOptions
作为依赖项,因此我们需要将提供程序定义为文字对象,并显式传递此依赖项。
Our TaskListComponent
can now be implemented. We will now open the src/app/task-list/task-list.component.ts
file and apply the code below:
我们的TaskListComponent
现在可以实现了。 现在,我们将打开src/app/task-list/task-list.component.ts
文件并应用以下代码:
This class gets TaskListService
injected and add a few callback methods to the Observables
responses. Both taskAdded$
and deleteTask$
triggers a call to loadTasks
method when the Observables
respond without errors. console.log
is triggered by these methods to handle cases where errors are issued by the serverless REST API.
此类注入TaskListService
,并向Observables
响应添加一些回调方法。 当Observables
响应无错误时, taskAdded$
和deleteTask$
触发对loadTasks
方法的调用。 这些方法触发console.log
来处理无服务器REST API发出错误的情况。
The loadTasks
method calls taskListService.loadTasks$
to assign the result to tasks
property.
loadTasks
方法调用taskListService.loadTasks$
将结果分配给tasks
属性。
With the three exposed methods and the task
property filled, we can now implement the TaskListComponent
interface, which resides in the src/app/task-list/task-list.component.html
file.
有了这三种公开方法并填充了task
属性,我们现在可以实现TaskListComponent
接口,该接口位于src/app/task-list/task-list.component.html
文件中。
This is what this file should look like:
该文件应如下所示:
Here we added a md-list
component, provided by Angular Material, that iterates through the tasks
, showing their creation date and their description. Also, each task got a button
that enables users to delete them.
在这里,我们添加了一个由Angular Material提供的md-list
组件,它遍历tasks
,显示tasks
的创建日期和描述。 此外,每个任务都有一个button
,使用户可以删除它们。
To make our interface better, let’s add two CSS rules to the src/app/task-list/task-list.component.css
file:
为了使我们的界面更好,让我们在src/app/task-list/task-list.component.css
文件中添加两个CSS规则:
This will make different tasks distinguishable with a gray background color, and push the delete button to the right, aligning it vertically to the task.
这将使不同的任务以灰色背景色区分,然后将删除按钮推向右侧,使其与任务垂直对齐。
Now our interface is ready to list tasks, so we need to make it visible by adding it to the src/app/app.component.html
file. Open it and the TaskListComponent
as follows:
现在我们的界面已准备好列出任务,因此我们需要通过将其添加到src/app/app.component.html
文件中使其可见。 如下所示打开它和TaskListComponent
:
If we open our application in a browser, by accessing http://localhost:4200
, we would see the following screen.
如果我们在浏览器中打开应用程序,则通过访问http://localhost:4200
,我们将看到以下屏幕。
Our app’s completion now depends on implementing the last component, TaskFormComponent
, to allow users to add tasks to their lists.
现在,我们的应用程序的完成取决于实现最后一个组件TaskFormComponent
,以允许用户将任务添加到他们的列表中。
To enable a user to add tasks, we need to open the src/app/task-list/task-form/task-form.component.ts
file and implement it as follows:
为了使用户能够添加任务,我们需要打开src/app/task-list/task-form/task-form.component.ts
文件并按以下方式实现:
This component accepts a user’s task input and emits a taskAdded
event with the data. This component's HTML, located in the src/app/task-list/task-form/task-form.component.html
file, is also really simple:
该组件接受用户的任务输入,并与数据一起发出taskAdded
事件。 位于src/app/task-list/task-form/task-form.component.html
文件中的该组件HTML也非常简单:
When clicked, the Add button triggers the addTask
method in the component. This method then triggers the taskAdded
event emitter. TaskListComponent
is the component that will listen to these events. We already implemented a method, called taskAdded
, that can handle such events. We just need to update this component's HTML to add TaskFormComponent
and register the event handler.
单击时,“ 添加”按钮将触发组件中的addTask
方法。 然后,此方法触发taskAdded
事件发射器。 TaskListComponent
是将侦听这些事件的组件。 我们已经实现了一个名为taskAdded
的方法,该方法可以处理此类事件。 我们只需要更新此组件HTML以添加TaskFormComponent
并注册事件处理程序即可。
To do that, let’s open src/app/task-list/task-list.component.html
and add the app-task-form
tag just before our list, as follows:
为此,我们打开src/app/task-list/task-list.component.html
并在列表之前添加app-task-form
标记,如下所示:
And here we go. Our app is now fully implemented and ready to go to production.
现在我们开始。 我们的应用现已完全实施,可以投入生产。
Or is it? If we play a little with the application we will see that under some conditions the user experience is not that good. The app takes a while to update the task list when a new task is added or an existing one gets deleted. So there is room for improvement.
还是? 如果我们稍微玩一下该应用程序,我们会发现在某些情况下用户体验不是很好。 当添加新任务或删除现有任务时,该应用程序需要一段时间才能更新任务列表。 因此,还有改进的空间。
To solve this issue let’s use a small module called Angular 2 Slim Loading Bar. To install it run npm install --save ng2-slim-loading-bar
and then open the src/app/app.module.ts
file to import it:
为了解决这个问题,我们使用一个名为Angular 2 Slim Loading Bar的小模块。 要安装它,请运行npm install --save ng2-slim-loading-bar
,然后打开src/app/app.module.ts
文件导入它:
We will also import its CSS rules by adding the following line to the top of our src/styles.css
file:
我们还将通过在src/styles.css
文件顶部添加以下行来导入其CSS规则:
After that we need to make our AppComponent
use SlimLoadingBarService
. To do that let's open src/app/app.component.ts
and edit as follows:
之后,我们需要使我们的AppComponent
使用SlimLoadingBarService
。 为此,我们打开src/app/app.component.ts
并进行如下编辑:
SlimLoadingBarService
contains two methods that we will use: start
, which starts the loading bar; and complete
, which ends the loading indicator. These methods will be registered as event listeners on TaskListComponent
. We still didn't create event emitters in this component, but we can configure the listeners in advance. Let's open src/app/app.component.html
and edit like this:
SlimLoadingBarService
包含两个我们将使用的方法: start
,它启动加载栏; 并且complete
,结束加载指示器。 这些方法将在TaskListComponent
上注册为事件侦听器。 我们仍然没有在此组件中创建事件发射器,但是我们可以预先配置侦听器。 让我们打开src/app/app.component.html
并进行如下编辑:
The last thing we will have to do is edit the src/app/task-list/task-list.component.ts
file to create and use both startAjaxRequest
and completeAjaxRequest
event emitters on TaskListComponent
:
我们要做的最后一件事是编辑src/app/task-list/task-list.component.ts
文件,以在TaskListComponent
上创建并使用startAjaxRequest
和completeAjaxRequest
事件发射器:
Here we have create both event emitters and have added them to the three methods that depend on AJAX request. Whenever one of these methods gets called we emit an event, through this.startAjaxRequest.emit()
, to make the Slim Loading Bar start running the loading bar indicator. After getting a response back from the AJAX requests sent by the loadTasks
method, that updates the task list, we tell Slim Loading Bar to complete its progress through this.completeAjaxRequest.emit()
.
在这里,我们创建了两个事件发射器,并将它们添加到了依赖于AJAX请求的三种方法中。 每当调用这些方法之一时,我们都会通过this.startAjaxRequest.emit()
发出一个事件,以使Slim Loading Bar开始运行加载条指示器。 在通过loadTasks
方法发送的AJAX请求获得响应并更新任务列表后,我们告诉Slim Loading Bar通过this.completeAjaxRequest.emit()
完成进度。
If we run our development server by issuing ng serve
and heading to http://localhost:4200/
, we will see our application with a better user experience:
如果我们通过发布ng serve
并转到http://localhost:4200/
来运行开发服务器,我们将看到具有更好用户体验的应用程序:
Our application is ready to be deployed to production. We have a persistence layer that saves all users’ tasks. We have a serverless REST API that accepts GET
, POST
and DELETE
requests to manipulate tasks. We have security, provided by Auth0. And we have a good looking Angular single page application interface. The only thing that is missing is a place to host our static (HTML, CSS and JavaScript) files.
我们的应用程序已准备好部署到生产中。 我们有一个持久层,可以保存所有用户的任务。 我们有一个无服务器的REST API,它接受GET
, POST
和DELETE
请求来操作任务。 我们拥有由Auth0提供的安全性。 我们有一个漂亮的Angular单页应用程序界面。 唯一缺少的是托管我们的静态(HTML,CSS和JavaScript)文件的地方。
That is exactly what GitHub Pages provides. To use it is simple. We just need to create a repository and push our work to a branch called gh-pages
. This branch should contain only our production bundles.
这正是GitHub Pages提供的 。 使用起来很简单。 我们只需要创建一个存储库并将我们的工作推送到gh-pages
分支即可。 该分支应仅包含我们的产品包。
To create a GitHub repository go to GitHub, sign in (or sign up if you don’t have an account) and choose the Create a New Repository option. Create your new repository naming it as task-list. Note that if you choose another name, you will have to adjust the base-href
parament of the ng build
command that we will run later.
要创建GitHub存储库,请访问GitHub ,登录(如果没有帐户,请注册),然后选择“ 创建新存储库”选项。 创建新的存储库,将其命名为task-list 。 请注意,如果您选择其他名称,则必须调整ng build
命令的base-href
参数,稍后我们将运行它。
Now we have to add this repository as a remote to our application. When we created our project with Angular CLI, it already came with Git. We just have to add this remote, commit all our changes and push to its master:
现在,我们必须将此存储库添加为应用程序的远程目录。 当我们使用Angular CLI创建项目时,它已经随Git一起提供了 。 我们只需要添加此远程服务器,提交所有更改并推送到其主服务器即可:
# adds new repo as a remote
git remote add origin git@github.com:YOUR-USERNAME/YOUR-REPO.git
# commits our code
git add .
git commit -m "Task List Angular app with a secure serverless REST API."
# push work to new repo
git push origin master
Having our code safe, we can now work on the going live task. Two steps are needed here. The first one is to prepare our code for production and package it. Again Angular CLI comes in handy. To do that we just have to issue ng build --prod --base-href=/task-list/
. Note that we have to set base-href
to the exact same name of our GitHub repository, otherwise our application won't be able to load all the resources and it won't work.
有了安全的代码,我们现在就可以进行实时任务。 这里需要两个步骤。 第一个是准备我们的代码以进行生产并将其打包。 Angular CLI再次派上用场。 为此,我们只需要发出ng build --prod --base-href=/task-list/
。 请注意,我们必须将base-href
设置为与GitHub存储库完全相同的名称,否则我们的应用程序将无法加载所有资源,并且将无法正常工作。
The second step used to be handled by Angular CLI, but this command has been removed in the latest release, so we will need a third party tool to help us here. Fortunately, there is one that is very easy to use called angular-cli-ghpages
. To install it issue npm install -g angular-cli-ghpages
. After that we just have to execute angular-cli-ghpages
(yep, without any parameters) and voilà. Our app is up and running on GitHub Pages.
第二步曾经由Angular CLI处理,但是此命令已在最新版本中删除 ,因此我们将需要第三方工具来帮助我们。 幸运的是,有一个非常容易使用的称为angular-cli-ghpages
。 要安装它,请发出npm install -g angular-cli-ghpages
。 之后,我们只需要执行angular-cli-ghpages
(是,没有任何参数)和voilà。 我们的应用程序已在GitHub Pages上启动并运行。
Important: do not forget to update the Allowed Callback URLs on your Auth0 account. The list of allowed URLs must have the URL where our app was exposed. This should be something like https://brunokrebs.github.io/task-list/
.
重要提示 :不要忘记更新Auth0帐户上的允许的回调URL 。 允许的URL列表必须包含公开我们应用程序的URL。 这应该类似于https://brunokrebs.github.io/task-list/
。
As we could see, when we choose the right tools, it gets easy to achieve great accomplishments. We started with nothing, just an idea to develop a task list application, and managed to create and release it to the internet with not that much effort.
如我们所见,选择正确的工具可以轻松实现出色的成就。 我们从一无所有开始,仅是开发任务列表应用程序的一个想法,然后设法创建了它并将其发布到Internet上的工作量不大。
We didn’t even have to worry about building, supporting and securing servers to host our web application or our database. If we had to manage these tasks by ourselves, we would take much more time and wouldn’t be as confident about our app’s security, fault tolerance and scalability.
我们甚至不必担心构建,支持和保护用于托管Web应用程序或数据库的服务器。 如果我们必须自己管理这些任务,我们将花费更多时间,并且对我们应用程序的安全性,容错性和可扩展性没有信心。
And this is just the beginning. Freeing ourselves from all these issues enables us to focus 100% on our ideas and on what makes our applications unique.
而这仅仅是个开始。 从所有这些问题中解放出来,使我们能够100%专注于我们的想法以及使我们的应用程序与众不同的因素。
I love reading and writing about development, mainly JavaScript and Java. If you want to share something with me, or want to stay tuned, you can reach me on Twitter. Also, feel free to add any comments here or in any of my articles.
我喜欢阅读和撰写有关开发的文章,主要是JavaScript和Java。 如果您想与我分享一些东西,或者想继续关注,可以在Twitter上与我联系。 另外,请随时在此处或我的任何文章中添加任何评论。
angular8 rest