preface
Serverless = Faas (Function as a service) + Baas (Backend as a service)
Serverless allows us to focus more on business development. Serverless solves some common server-side problems:
- Serverless does not need to set up the server environment and deliver environment variables to keep the environment of each machine consistent (Serverless mechanism is naturally replicable)
- Serverless Does not need to estimate the traffic. It cares about resource utilization, backup and DISASTER recovery, and capacity expansion. (Serverless can dynamically expand capacity based on traffic and charge based on actual requests.)
- Serverless does not need to worry about memory leaks (Serverless cloud functions will be destroyed after the service is finished)
- Serverless has complete supporting services, such as cloud database, cloud storage, cloud message queue, cloud audio and video and cloud AI services, etc. Good use of these cloud services can greatly reduce our workload
The first three points above are the category of Faas and the fourth is the category of Baas. Simply speaking, Serverless can be understood as a system that can upload or edit a function online. The operating environment of this function is provided by the system. When a request is made, the system will automatically start a function for service. Functions can call various existing cloud service apis to simplify development and maintenance costs.
Read a lot of articles about Serverless, most of them are about architecture, about the implementation of Serverless itself. In this paper, a simple and clear example of a simple blog system in Tencent cloud Serverless landing, will only involve Faas and Baas practice part.
Let’s get started
Simple blog system features summary
As shown in the sequence diagram above, the simple blog system implemented this time has only blog list page and blog content page, which does not involve comments and login. It focuses on Serverless landing related content, such as how to write the cloud function itself, how to develop locally, how to associate with the custom domain name, how to access cloud MySQL. How to organize code within cloud functions such as Router, Controller, Service, Model, View, etc.
With these questions in mind, let’s begin
Initialization and basic configuration of cloud functions
Visit here and click Use Now to enter the cloud function:
In order to make you not afraid, first hand in the bottom, Tencent cloud function has 1 million times a month to call the free amount, personal learning to use completely enough.
Ok, let’s move on
After clicking “Use now” in the image above, we can see the overview of cloud functions:
Click the function service on the left, and in the interface that appears, click New:
The page shown in the screenshot below appears. Input the function name, select the language, and select an initialization from the function template. Here, I choose the lower right corner of “National Day SCF operation promotion activity Demo”. File consolidation and so on, lowering our entry costs.
After selecting the template, click Next, which brings up the screen to set environment variables and network environment
Click “finish” to create a cloud function. See the effect. Although it is a cloud function, it is not only a single file, but can be organized in the form of multiple files:
If you look at the code, it is very simple to do, according to the cloud function standard, expose a main_handler, which reads an HTML page template, uses the render function to parse the HTML template + data into an HTML string, and returns it.
So how do we access this cloud function?
The answer is to configure the trigger mode. We set the trigger mode to API gateway trigger as follows:
Here are some of the concepts in the diagram:
- Timing trigger: Usually used for some scheduled tasks, such as periodically sending emails, running data, and sending reminders.
- COS is Tencent cloud storage, for example, pictures and videos can be stored with COS. COS trigger means that after uploading files to COS, this function will be triggered. At this time, this function can be used to compress pictures and transcode videos.
- Ckafka trigger is triggered when there is new data in the Ckafka message queue.
- The API gateway triggers this function when a request comes in.
Here we choose API gateway trigger, which is the function that fires when a request comes in.
After saving, we can see the access path of the cloud function:
Here is a link from my example to give you a taste of it
Access the link
Above is our initial understanding of cloud function, next we step by step, take you to create a simple blog system
Tencent Serverless Toolkit for VS Code
First, we need a native development environment, although the online editor experience is similar to vscode, after all, native code editing is configured to work better. How do we publish cloud functions if we modify the code locally?
Take VSCode as an example, we need to install “Tencent Serverless Toolkit for VSCode “. You can search for the installation in the PLUG-IN of VSCode, and there will be detailed installation instructions on the plug-in home page, which will not be described here.
The plug-in interface is shown as follows:
After the installation, there will be an icon for the cloud function on the left. With this plugin you can:
- Pull the list of cloud functions in the cloud and trigger the cloud function to run in the cloud.
- Quickly create a cloud function project locally.
- Develop, debug, and test your cloud function code locally.
- Use simulated COS, CMQ, CKafka, API gateway and other trigger events to trigger the function to run.
- Upload the function code to the cloud and update the function configuration.
Usually, the front-end code needs to be packaged, and NPM install, NPM run build and so on are implemented. The cloud function does not provide this environment, so we can release the code through this plug-in after being packaged locally. Of course, we can also use the continuous integration tool, run the CLI to publish, this will not expand into.
Database selection and design
Database selection
Here is the choice of Tencent cloud MySQL basic version of the minimum, a month only 29 yuan ~. Of course, it is also possible to build a database for external exposure for learning. However, if you want to use it for a long time, in order to facilitate maintenance and ensure data stability, it is recommended to choose cloud MySQL. Cloud MySQL doesn’t need us to worry about installation and data loss due to machine hang-ups. Out of the box is also a feature of Baas.
Note that the selected networks are default-VPC and default-subnet, which must be consistent with the cloud function. Otherwise, the cloud function cannot access MySQL, as shown in the figure below:
Cloud functions can access MySQL through this IP and port:
Database design
Because it is a simple blog system, which does not involve login and comments, on the basis of satisfying the third paradigm of database design, we only need to design a table, namely the blog table itself:
The field name | The field type |
---|---|
id | A primary key |
title | The title |
content | The article content |
createdAt | Creation time |
updatedAt | Modify the time |
Behind because we will use the MySQL Node. Js ORM framework Sequelize to manipulate the database, the database table is created automatically, here we will no longer show ~
How to connect to and operate a database
Cloud function custom domain name mapping to API gateway
Domain name resolution
As mentioned above, after the cloud function is created and configured with API gateway trigger, it can be accessed from the extranet, but the default URL is completely unmemorizable, which is not conducive to propagation. We need a custom domain name. How to buy domain name here is not launched, you can refer to this official document to buy, cheap only 5 yuan a year ~
Here’s how to bind a custom domain name to a cloud function:
After purchasing a domain name, we need to add domain name resolution to the domain name resolution list:
As shown in the figure below, add @ and WWW CNAME to our cloud function domain name, which is equivalent to assigning individual names to the domain name of the cloud function. If you access the self-defined domain name, you can access the resolved IP of the cloud function domain name:
Note that the recorded value only needs to be filled in the domain name of the cloud function, and neither path nor protocol is required
API Gateway Mapping
It is not enough to resolve the custom domain name to the cloud function domain name, we also need to map the path, we open the API gateway service, click our cloud function service name, open the custom domain name, click New:
After following the operation in the screenshot, we can access the cloud function with our own domain name on the extranet
Here is the simple blog address for the final implementation of this article: www.momentfly.com/
Routing design in cloud functions
As we mentioned earlier, the implementation of a simple blog system with two pages can be implemented using two cloud functions for two pages, but this implementation is not elegant because the code cannot be reused. For example, some common methods we write for handling pages have to be implemented in both functions. And node_modules must exist in both cloud functions, wasting space.
So we have to organize the code for the two pages in a function. The easiest thing to think of is to write a simple judgment, if path is /, return the blog list page, else if path is /post, return the blog content page. But it’s still not very elegant. To get the path, write a bunch of if and else routes, which is not very maintainable, and if you want to expand, you have to add get, POST, and so on, plus you have to write functions to get the parameters of the path.
Can you organize your code as easily as Express or KOA? The answer is yes!
If we compare AWS Lambda (Amazon Cloud Function), we will find that Tencent Cloud function and AWS Lambda are consistent in terms of entry parameters. We can realize koA access through serverless-HTTP library. The library was originally built for AWS Lambda, but works seamlessly with Tencent Cloud functions.
As mentioned above, the cloud function entry code main_handler is as follows:
exports.main_handler = async (event, context, callback) => {
}
Copy the code
We pulled the code locally, installed KOA, KOA-Router, serverless-HTTP, and organized koA seamlessly:
const Koa = require("koa");
const serverless = require("serverless-http");
const app = new Koa();
const router = require('./router');
app
.use(router.routes())
.use(router.allowedMethods())
const handler = serverless(app);
exports.main_handler = async (event, context, callback) => {
return awaithandler( { ... event,queryStringParameters: event.queryString },
context
);
}
Copy the code
Our router file is written as koA normally:
const Router = require('koa-router');
const { homeController } = require('.. /controllers/home')
const { postController } = require('.. /controllers/post')
const router = new Router();
router
.get('/', homeController)
.get('/post', postController)
module.exports = router;
Copy the code
Seeing this, those familiar with KOA have grasped the main idea of the chapter and understood one way of Serverless landing. But next will be a complete blog system to build the logic of the relevant to explain clearly, interested students continue to read ~
Organization of code in cloud functions
In the same way that normal KOA applications are organized, code is usually organized into Router, Controller, Service, Model, View, etc. With koA plugged in via Serverless-HTTP, our cloud function services are organized exactly like traditional KOA applications. Let’s take a look at the complete project catalog:
Blog / ├ ─ ─ controllers | ├ ─ ─ home | | └ ─ ─ index. The js | └ ─ ─ post | └ ─ ─ index. The js ├ ─ ─ index. The js ├ ─ ─ model | ├ ─ ─ the js | └ ─ ─ Index. Js ├ ─ ─ package. Json ├ ─ ─ the router | └ ─ ─ index. The js ├ ─ ─ services | ├ ─ ─ assets | | └ ─ ─ index. The js | ├ ─ ─ data | | └ ─ ─ Index. Js | ├ ─ ─ home | | └ ─ ─ render. Js | ├ ─ ─ post | | └ ─ ─ render. Js | └ ─ ─ the response | └ ─ ─ index. The js ├ ─ ─ the template. The yaml ├ ─ ─ The view | ├ ─ ─ making - markdown. CSS | ├ ─ ─ home | | ├ ─ ─ home. CSS | | └ ─ ─ home. HTML | └ ─ ─ post | ├ ─ ─ post. CSS | └ ─ ─ post. HTML └ ─ ─ yarn. The lockCopy the code
Controller
A Controller should clearly reflect the processing of a request, and some implementation details should be encapsulated in a Service, which is especially important in projects with complex processes.
The Controller for our two pages is simple:
Controllers/home/index. Js – blog list page
const render = require('.. /.. /services/home/render');
const { getBlogList } = require('.. /.. /services/data')
const { htmlResponse } = require('.. /.. /services/response')
exports.homeController = async (ctx) => {
const blogList = await getBlogList() // Get data
const html = render(blogList) // Data + template generates HTML
htmlResponse(ctx, html) // Return the HTML process
}
Copy the code
Controllers/post/index. Js – blog content
const render = require('.. /.. /services/post/render');
const { getBlogById } = require('.. /.. /services/data')
const { htmlResponse } = require('.. /.. /services/response')
exports.postController = async (ctx) => {
const { id } = ctx.query
const blog = await getBlogById(id)
const html = render(blog)
htmlResponse(ctx, html)
}
Copy the code
As you can see, our controllers have only three steps, i.e
- To get the data
- Data + template generates HTML
- Returns the HTML
We will explain the implementation of these three steps in the following Services.
Services
In this simple blog system, the blog list page is similar to the content page, so the code will be relatively similar. Here we choose the blog list page to say Services:
All controllers get data first. Let’s look at data services:
/services/data/index.js
const { Blog } = require('.. /.. /model')
exports.getBlogList = async() = > {await Blog.sync({}); // If the table does not exist, it is automatically created, a feature of Sequelize
return await Blog.findAll();
}
exports.getBlogById = async (blogId) => {
await Blog.sync({});
return await Blog.findOne({
where: {
id: blogId,
}
})
}
Copy the code
To get the list of blogs and the front page of the Blog, we await blog.findall (), await blog.findone with the defined Model, i.e. Blog.
After obtaining the data, we need to perform the stitching of data and HTML template according to the process of Controller above, let’s see the render service:
services/home/render.js
const template = require('art-template');
const marked = require('marked');
const hljs = require('highlight.js');
const { markdownCss, hightlightCss, resolveAssetsFromView } = require('.. /assets');
const homeHtml = resolveAssetsFromView('./home/home.html');
const homeCss = resolveAssetsFromView('./home/home.css');
module.exports = (blogList) = > {
marked.setOptions({
highlight: function (code, lang) {
returnhljs.highlight(lang, code).value; }});let html = template.render(homeHtml, {
blogList: blogList.map((blog) = > {
blog.content = marked(blog.content);
return blog;
}),
markdownCss,
hightlightCss,
homeCss,
})
return html
}
Copy the code
Here we use art-template, a high-performance templating engine.
Use a template engine to process HTML templates and data instead of React and Vue because simple blogging systems are too simple to use frameworks. Besides, the original intention of this simple blog system focuses on Serverless practice. Using React, Vue or simple template engine has no impact on Serverless practice. If react and Vue are used as SSR, another topic needs to be opened to explain.
-
Marked is a library that converts a markdown string to an HTML string, such as # hello to
hello
-
Highlight.js is used to highlight code in Markdown
-
MarkdownCss, hightlightCss, homeCss, are written CSS files, read out with FS file content strings
The key sentence, art-template, HTML template, data (blogList, CSS) render HTML
let html = template.render(homeHtml / * * / template, { /* Template variable */
/ / data
blogList: blogList.map((blog) = > {
blog.content = marked(blog.content); // Markdown processing
return blog;
}),
// For templates, the following data is also data, but the data content is CSS strings
markdownCss,
hightlightCss,
homeCss,
});
Copy the code
MarkdownCss, hightlightCss and homeCss are processed by assets.
/services/assets/index.js
const fs = require('fs');
const path = require('path');
const hightlightCss = fs.readFileSync(path.resolve(__dirname, '.. /.. /node_modules/highlight.js/styles/atom-one-light.css'), {
encoding: 'utf-8',})const markdownCss = fs.readFileSync(path.resolve(__dirname, '.. /.. /view/github-markdown.css'), {
encoding: 'utf-8',})const resolveAssetsFromView = (relativePath) = > {
// An auxiliary function to read a file as a string from view
const filePath = path.resolve(__dirname, '.. /.. /view', relativePath);
console.log(`filePath: ${filePath}`);
return fs.readFileSync(filePath, {
encoding: 'utf-8'})},module.exports = {
hightlightCss,
markdownCss,
resolveAssetsFromView
}
Copy the code
With fs.readfilesync (), the file is read utF-8 and exposed along with auxiliary functions.
To the last step of the Controller, which returns the HTML, we use response Service to do this:
/services/response/index.js
exports.htmlResponse = (ctx, html) = > {
ctx.set('Content-Type'.'text/html');
ctx.body = html
ctx.status = 200
}
Copy the code
Model
The data service above, through the Blog Model can easily obtain data, that Blog Model implementation is what? Let’s take a look:
/model/index.js
const { Sequelize, sequelize, Model } = require('./db');
class Blog extends Model { }
Blog.init({
title: { // Define the title field
type: Sequelize.STRING, // A string of characters
allowNull: false // Null is not allowed
},
content: {
type: Sequelize.TEXT('medium'), / / mysql MEDIUMTEXT
allowNull: false // Null is not allowed
}
}, {
sequelize,
modelName: 'blog'
});
module.exports = {
Blog,
}
Copy the code
We use Sequelize, an ORM library, to simplify MySQL operations, eliminating the need for hand-written SQL statements, and the library itself protects against SQL injection.
Blog.init initializes the Blog. The model. id, createdAt, and updatedAt fields don’t need to be declared. Sequelize automatically creates them for us.
Let’s look at the DB implementation
/model/db.js
const Sequelize = require('sequelize');
const sequelize = new Sequelize('blog'.'root', process.env.password, {
host: '172.16.0.15'.dialect: 'mysql'
});
const Model = Sequelize.Model;
module.exports = {
Sequelize,
sequelize,
Model,
}
Copy the code
Blog is the name of the database, root is the login account, and the password is stored in the environment variable, which is obtained through process.env.password, which is the environment variable we filled in when creating the cloud function.
View
The view layer is only the CSS and HTML template. CSS is not covered. Here is the art-template template:
/view/home/home.html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>serverless blog demo</title>
<style>{{markdownCss}} {{hightlightCss}} {{homeCss}}</style>
</head>
<body>
<div class="blog-home">
{{each blogList}}
<div class="post" onclick="location.href='./post? id={{$value.id}}'">
<h1>{{$value.title}}</h2>
<div class="markdown-body">{{@ $value.content}}</div>
</div>
{{/each}}
</div>
</body>
</html>
Copy the code
{{}} is the template variable, and the second parameter of the preceding render method can be retrieved from {{}}.
The above is the code logic of our simple blog system. At present, there are only two pages of code. If you want to add a blog creation page, the process is consistent, and you can add the relevant Router, Controller and Service. At present, I write the data directly through the database operation interface of Tencent cloud.
If we want to add comment function, we need to add a new table to store, of course, later you can expand as you wish ~
Implementation effect
www.momentfly.com/
summary
By building a simple blog system, we learned a practice of Serverless. During this period, it involves how to create cloud functions, introduces the local VSCode cloud function plug-in, cloud function self-defined domain name and API gateway mapping, cloud database creation and connection, cloud function code organization, etc. The whole process is very lightweight and does not involve much server o&M. The rise of Serverless will bring great convenience to our development. In the future, major cloud service providers will also improve Serverless services and bring better DevOps experience.
Finally, let’s embrace Serverless and get your hands dirty
Possible potholes
Some friends see here has been itching to try, in the process of starting may encounter a little problem, here is the unified say:
Local debugging
We can simulate the API gateway locally. We need to customize the method, path and parameters of the request, as shown in the picture below. We can click “Add Test Template” to configure it
In addition, simple blog system in the local to run, need to connect to the local MySQL, you can modify the simulated request test template, pass specific parameters to mark the environment, so as to request the local MySQL.
In addition, some friends directly upload the code in the public account to their cloud function, found that it does not run, here should pay attention to do not replace their function template.yaml. Because template.yaml is unique to each cloud function, it marks the basic configuration of cloud functions, such as memory limits, environment variables, trigger configuration, and so on.
Routes with non-custom domain names
Some partners have not customized domain name, through the cloud function default API gateway URL can also be accessed, but we should pay attention to the routing:
Service-20z5jnak-1253736472.gz.apigw.tencentcs.com/release/you…
This URL up here, the route is
router
.get("/yourFunctionName", homeController)
Copy the code
Full Demo
To obtain the complete demo code, you can reply to serveless or code or Demo
The last
- Welcome to add my wechat (Winty230), pull you into the technology group, long-term exchange learning…
- Welcome to pay attention to “front-end Q”, seriously learn front-end, do a professional technical people…