{"componentChunkName":"component---src-templates-blog-detail-tsx","path":"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb","result":{"data":{"currentBlog":{"id":"8d3e0a32-3028-5f67-b38e-9088a83b37ab","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020115/1579078112543-1577769064015-joshua-aragon-FGXqbqbGt5o-unsplash.jpg","authors":["Aceyclee"],"categories":["guides-and-tutorials"],"date":"2019-12-17T00:00:00.000Z","title":"使用 Serverless Framework，结合云函数 SCF、API 网关和云数据库 MySQL 构建 REST API","description":"本文介绍如何创建一个进行自动化面试评估的 Serverless 应用！","authorslink":["https://www.zhihu.com/people/Aceyclee"],"translators":null,"translatorslink":null,"tags":["Node.js","API 网关"],"keywords":"Serverless 自动化面试评估,Serverless 云数据库 MySQL,云函数 SCF","outdated":null},"wordCount":{"words":259,"sentences":62,"paragraphs":62},"fileAbsolutePath":"/opt/build/repo/content/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb.md","fields":{"slug":"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/","keywords":["java","nodejs","serverless","无服务器","云函数","candidate","Serverless","serverless","dev","candidateSubmission","service"]},"html":"<p>Serverless 字面意思是「无服务器」。根据语境的不同，Serverless 可能有不同的解读方\n法：比如它可能意味着使用 Firebase 等第三方托管的服务，也可能是腾讯云等云厂商提供\n的计算服务，或者可能是构建 Serverless 应用中所用到的无服务器框架。具体解读可参考\n：<a href=\"https://serverlesscloud.cn/blog/2019-08-01-serverless-basic-concept/\">Serverless 基础概念入门</a></p>\n<p>本文将介绍如何使用云函数 SCF、API 网关、云数据库 MySQL 和 Serverless Framework\n构建 REST API。</p>\n<p><strong>简单介绍一下：</strong></p>\n<ul>\n<li><a href=\"https://cloud.tencent.com/product/scf\">云函数 SCF</a>：\n腾讯云为开发者提供的无服务器执行环境，用户只需使用平台支持的语言编写核心代码并\n设置代码运行的条件，即可在腾讯云基础设施上弹性、安全地运行代码。SCF 目前支持\nJava、Python、Node.js 和 PHP 等。</li>\n<li><a href=\"https://github.com/serverless/serverless\">Serverless Framework</a>：在 GitHub 上\n有三万颗星，业界非常受欢迎的无服务器应用框架，开发者无需关心底层资源即可部署完\n整可用的 Serverless 应用架构。</li>\n</ul>\n<h2 id=\"应用：serverless-编程面试评估器\"><a href=\"#%E5%BA%94%E7%94%A8%EF%BC%9Aserverless-%E7%BC%96%E7%A8%8B%E9%9D%A2%E8%AF%95%E8%AF%84%E4%BC%B0%E5%99%A8\" aria-label=\"应用：serverless 编程面试评估器 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>应用：Serverless 编程面试评估器</h2>\n<p>在我目前团队的面试中，有一项是测验候选人的代码能力。我们会先给候选人布置一个一周\n完成的小作业，然后我们会评估作业的完成情况，来测试候选人是否足够优秀。</p>\n<p>我们打算把评估过程自动化，即使没有人干预，也能筛选出不合适的候选人。毕竟，能够自\n动化完成的任务就应该自动化。下面是这个应用的工作流程：</p>\n<ol>\n<li>团队将候选人的详细信息提交给系统；</li>\n<li>系统根据候选人的技能和经验发送出一封带有标记的作业邮件，作业中包含了 Gradle\n或者 Maven project 等；</li>\n<li>候选人编写代码并交付作业 (eg: <code class=\"language-text\">gradle submitAssignment</code>)，然后压缩候选人的源\n码并提交到系统；</li>\n<li>收到作业后，系统将构建项目并运行所有的测试用例；</li>\n<li>如果构建失败，候选人状态标记为 failed，并反馈给招聘团队</li>\n<li>如果构建成功，我们将测试代码覆盖率，如果小于某个值，则标记 failed 并通知团队</li>\n<li>如果构建成功并且代码覆盖率达标，那么我们将分析代码并计算代码质量得分，低于某\n个分数则标记 failed。反之则通过代码测试进入终面。</li>\n</ol>\n<p>在本教程中，我们将构建一个 REST API 来存储候选者的详细信息，并从头开始构建一个完整的\nServerless 应用。</p>\n<h2 id=\"动手准备\"><a href=\"#%E5%8A%A8%E6%89%8B%E5%87%86%E5%A4%87\" aria-label=\"动手准备 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>动手准备</h2>\n<p>完成本教程之前，首先确保系统包含以下环境：</p>\n<ol>\n<li>一个可用的 <a href=\"https://cloud.tencent.com/login\">腾讯云账户</a></li>\n<li><a href=\"https://nodejs.org/en/\">Node.js</a> (版本号不低于 8.6，建议使用 10.0 及以上)</li>\n<li><a href=\"https://github.com/serverless/serverless\">Serverless Framework</a></li>\n</ol>\n<p>通过以下命令安装 Serverless Framework：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ npm install -g serverless</code></pre></div>\n<p>你可以使用命令缩写 <code class=\"language-text\">sls</code> 来代替 <code class=\"language-text\">serverless</code>。</p>\n<h2 id=\"step-1：创建一个-nodejs-无服务器项目\"><a href=\"#step-1%EF%BC%9A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA-nodejs-%E6%97%A0%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%A1%B9%E7%9B%AE\" aria-label=\"step 1：创建一个 nodejs 无服务器项目 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 1：创建一个 Node.js 无服务器项目</h2>\n<p>创建目录 <code class=\"language-text\">coding-round-evaluator</code> 并进入该目录：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ mkdir coding-round-evaluator &amp;&amp; cd coding-round-evaluator</code></pre></div>\n<p>在该目录下，我们开始搭建第一个微服务，它将保存候选人的详细信息，列出候选者并获取\n单个候选者的信息：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ sls create --template tencent-nodejs --path candidate-service --name candidate</code></pre></div>\n<p>文件 <code class=\"language-text\">candidate-service</code> 的目录结构如下：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">.\n├── index.js\n├── package.json\n└── serverless.yml</code></pre></div>\n<p>我们来看看这三个文件：</p>\n<ol>\n<li><strong>index.js</strong>：定义了你的云函数；</li>\n<li><strong>package.json</strong>：定义了该服务所依赖的其他库；</li>\n<li><strong>serverless.yml</strong>：定义 Serverless Framework 创建服务所用的资源配置。</li>\n</ol>\n<h2 id=\"step-2：创建用于提交候选人的-rest-资源\"><a href=\"#step-2%EF%BC%9A%E5%88%9B%E5%BB%BA%E7%94%A8%E4%BA%8E%E6%8F%90%E4%BA%A4%E5%80%99%E9%80%89%E4%BA%BA%E7%9A%84-rest-%E8%B5%84%E6%BA%90\" aria-label=\"step 2：创建用于提交候选人的 rest 资源 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 2：创建用于提交候选人的 REST 资源</h2>\n<p>我们先配置 serverless.yml 文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"55521302768246940000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`service: candidate # 定义服务名称\n\nprovider: # 云厂商相关配置\n  name: tencent\n  runtime: Nodejs8.9 # Nodejs8.9 or Nodejs6.10\n  credentials: ~/credentials\n\nplugins:\n  - serverless-tencent-scf\n\nfunctions: # 定义了 candidateSubmission 的功能\n  candidateSubmission:\n    handler: candidate.submit\n    events:\n      - apigw:\n          name: api\n          parameters:\n            stageName: release\n            serviceId:\n            httpMethod: POST`, `55521302768246940000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">service</span><span class=\"token punctuation\">:</span> candidate <span class=\"token comment\"># 定义服务名称</span>\n\n<span class=\"token key atrule\">provider</span><span class=\"token punctuation\">:</span> <span class=\"token comment\"># 云厂商相关配置</span>\n  <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> tencent\n  <span class=\"token key atrule\">runtime</span><span class=\"token punctuation\">:</span> Nodejs8.9 <span class=\"token comment\"># Nodejs8.9 or Nodejs6.10</span>\n  <span class=\"token key atrule\">credentials</span><span class=\"token punctuation\">:</span> ~/credentials\n\n<span class=\"token key atrule\">plugins</span><span class=\"token punctuation\">:</span>\n  <span class=\"token punctuation\">-</span> serverless<span class=\"token punctuation\">-</span>tencent<span class=\"token punctuation\">-</span>scf\n\n<span class=\"token key atrule\">functions</span><span class=\"token punctuation\">:</span> <span class=\"token comment\"># 定义了 candidateSubmission 的功能</span>\n  <span class=\"token key atrule\">candidateSubmission</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> candidate.submit\n    <span class=\"token key atrule\">events</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">apigw</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> api\n          <span class=\"token key atrule\">parameters</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">stageName</span><span class=\"token punctuation\">:</span> release\n            <span class=\"token key atrule\">serviceId</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">httpMethod</span><span class=\"token punctuation\">:</span> POST</code></pre></div>\n<p>现在，在 <code class=\"language-text\">candidate-service</code> 中创建一个新的 <code class=\"language-text\">api</code> 目录，将 <code class=\"language-text\">handler.js</code> 移到 <code class=\"language-text\">api</code> 目录。重命名 <code class=\"language-text\">index.js</code> 为\n<code class=\"language-text\">candidate.js</code>；重命名 <code class=\"language-text\">handle</code> 为 <code class=\"language-text\">submit</code>.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"76705782971652370000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`'use strict';\n\nmodule.exports.submit = (event, context, callback) => {\n  const response = {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: 'Go Serverless v1.0! Your function executed successfully!',\n      input: event,\n    }),\n  };\n\n  callback(null, response);\n};`, `76705782971652370000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token string\">'use strict'</span><span class=\"token punctuation\">;</span>\n\nmodule<span class=\"token punctuation\">.</span>exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">submit</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">,</span> callback</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    statusCode<span class=\"token punctuation\">:</span> <span class=\"token number\">200</span><span class=\"token punctuation\">,</span>\n    body<span class=\"token punctuation\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      message<span class=\"token punctuation\">:</span> <span class=\"token string\">'Go Serverless v1.0! Your function executed successfully!'</span><span class=\"token punctuation\">,</span>\n      input<span class=\"token punctuation\">:</span> event<span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>在执行部署前，需要安装 <code class=\"language-text\">serverless</code> 插件 <code class=\"language-text\">serverless-tencent-scf</code>：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ npm i serverless-tencent-scf --save-dev</code></pre></div>\n<p>执行 <code class=\"language-text\">serverless deploy</code> 命令进行部署：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ sls deploy --debug</code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Serverless: Packaging service...\nServerless: Excluding development dependencies...\nServerless: Creating Stack...\nServerless: Checking Stack create progress...\n.....\nServerless: Uploading service package to cos[sls-cloudfunction-ap-guangzhou]. candidate-dev-FahKxK-2019-12-25-16-54-31.zip\nServerless: Uploaded package successful /Users/yugasun/Desktop/Develop/@yugasun/mysql-demo/.serverless/candidate.zip\nServerless: Creating function candidate-dev-candidateSubmission\nServerless: Created function candidate-dev-candidateSubmission\nServerless: Setting tags for function candidate-dev-candidateSubmission\nServerless: Creating trigger for function candidate-dev-candidateSubmission\nServerless: Created apigw trigger candidate-dev-candidateSubmission_apigw for function candidate-dev-candidateSubmission success. service id service-nld6x64o url https://service-nld6x64o-1251556596.gz.apigw.tencentcs.com/release/candidate-dev-candidateSubmission\nServerless: Deployed function candidate-dev-candidateSubmission successful\nServerless: Service Information\nservice: candidate\nstage: dev\nregion: ap-guangzhou\nstack: candidate-dev\nresources: 1\nfunctions:   candidateSubmission: candidate-dev-candidateSubmission\n    POST - https://service-nld6x64o-1251556596.gz.apigw.tencentcs.com/release/candidate-dev-candidateSubmission</code></pre></div>\n<p>现在，POST 操作可用了，您可以使用 cURL 等工具来发出 POST 请求。</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ curl -X POST https://service-nld6x64o-1251556596.gz.apigw.tencentcs.com/release/candidate-dev-candidateSubmission</code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{&quot;message&quot;:&quot;Go Serverless v1.0! Your function executed successfully!&quot;, &quot;input&quot;:{...}}</code></pre></div>\n<h2 id=\"step-3：将数据保存到云数据库-mysql-上\"><a href=\"#step-3%EF%BC%9A%E5%B0%86%E6%95%B0%E6%8D%AE%E4%BF%9D%E5%AD%98%E5%88%B0%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93-mysql-%E4%B8%8A\" aria-label=\"step 3：将数据保存到云数据库 mysql 上 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 3：将数据保存到云数据库 MySQL 上</h2>\n<p>在开始连接数据库之前，你需要先创建一个 MySQL 实例，然后初始化数据库\n<code class=\"language-text\">serverless</code>。</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"39173869446871560000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`provider: # 云厂商相关配置\n  name: tencent\n  region: ap-guangzhou\n  role: QCS_SCFFull # You must add a role who can connect to your clound mysql\n  runtime: Nodejs8.9 # Nodejs8.9 or Nodejs6.10\n  timeout: 60\n  vpcConfig: # you must set vpc config for mysql connnect\n    vpcId: vpc-xxx\n    subnetId: subnet-xxx\n  environment:\n    variables:\n      DB_HOST: 127.0.0.1\n      DB_USER: root\n      DB_PORT: 3306\n      DB_PASSWORD: 123\n      DB_DATABASE: serverless\n\nfunctions: # 定义了 candidateSubmission 的功能\n  candidateSubmission:\n    handler: candidate.submit\n    events:\n      - apigw:\n          name: api\n          parameters:\n            stageName: release\n            serviceId: xxx\n            httpMethod: POST`, `39173869446871560000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">provider</span><span class=\"token punctuation\">:</span> <span class=\"token comment\"># 云厂商相关配置</span>\n  <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> tencent\n  <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>guangzhou\n  <span class=\"token key atrule\">role</span><span class=\"token punctuation\">:</span> QCS_SCFFull <span class=\"token comment\"># You must add a role who can connect to your clound mysql</span>\n  <span class=\"token key atrule\">runtime</span><span class=\"token punctuation\">:</span> Nodejs8.9 <span class=\"token comment\"># Nodejs8.9 or Nodejs6.10</span>\n  <span class=\"token key atrule\">timeout</span><span class=\"token punctuation\">:</span> <span class=\"token number\">60</span>\n  <span class=\"token key atrule\">vpcConfig</span><span class=\"token punctuation\">:</span> <span class=\"token comment\"># you must set vpc config for mysql connnect</span>\n    <span class=\"token key atrule\">vpcId</span><span class=\"token punctuation\">:</span> vpc<span class=\"token punctuation\">-</span>xxx\n    <span class=\"token key atrule\">subnetId</span><span class=\"token punctuation\">:</span> subnet<span class=\"token punctuation\">-</span>xxx\n  <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">DB_HOST</span><span class=\"token punctuation\">:</span> 127.0.0.1\n      <span class=\"token key atrule\">DB_USER</span><span class=\"token punctuation\">:</span> root\n      <span class=\"token key atrule\">DB_PORT</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3306</span>\n      <span class=\"token key atrule\">DB_PASSWORD</span><span class=\"token punctuation\">:</span> <span class=\"token number\">123</span>\n      <span class=\"token key atrule\">DB_DATABASE</span><span class=\"token punctuation\">:</span> serverless\n\n<span class=\"token key atrule\">functions</span><span class=\"token punctuation\">:</span> <span class=\"token comment\"># 定义了 candidateSubmission 的功能</span>\n  <span class=\"token key atrule\">candidateSubmission</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> candidate.submit\n    <span class=\"token key atrule\">events</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">apigw</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> api\n          <span class=\"token key atrule\">parameters</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">stageName</span><span class=\"token punctuation\">:</span> release\n            <span class=\"token key atrule\">serviceId</span><span class=\"token punctuation\">:</span> xxx\n            <span class=\"token key atrule\">httpMethod</span><span class=\"token punctuation\">:</span> POST</code></pre></div>\n<p>安装依赖：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ npm install --save mysql2\n$ npm install --save uuid</code></pre></div>\n<p>更新 <code class=\"language-text\">api/candidate.js</code>：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"42617788855833805000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`'use strict';\n\nconst uuid = require('uuid');\nconst mysql = require('mysql2');\n\n// init mysql connection\nfunction initMysqlPool() {\n  const { DB_HOST, DB_PORT, DB_DATABASE, DB_USER, DB_PASSWORD } = process.env;\n\n  const promisePool = mysql\n    .createPool({\n      host: DB_HOST,\n      user: DB_USER,\n      port: DB_PORT,\n      password: DB_PASSWORD,\n      database: DB_DATABASE,\n      connectionLimit: 1,\n    })\n    .promise();\n  promisePool.query(\n    \\`CREATE TABLE IF NOT EXISTS candidates (\n    id          VARCHAR(64)        NOT NULL,\n    fullname    TEXT          NOT NULL,\n    email       VARCHAR(64)      NOT NULL,\n    experience  INT UNSIGNED  NOT NULL,\n    submittedAt VARCHAR(64)      NOT NULL,\n    updatedAt   VARCHAR(64)      NOT NULL\n  );\\`,\n  );\n\n  return promisePool;\n}\n\nconst pool = initMysqlPool();\n\nmodule.exports.submit = async (event, context, callback) => {\n  const requestBody = JSON.parse(event.body);\n  const fullname = requestBody.fullname;\n  const email = requestBody.email;\n  const experience = requestBody.experience;\n\n  if (\n    typeof fullname !== 'string' ||\n    typeof email !== 'string' ||\n    typeof experience !== 'number'\n  ) {\n    console.error('Validation Failed');\n    callback(\n      new Error(&quot;Couldn't submit candidate because of validation errors.&quot;),\n    );\n    return;\n  }\n\n  const timestamp = new Date().getTime();\n  const candidate = {\n    id: uuid.v4(),\n    fullname: fullname,\n    email: email,\n    experience: experience,\n    submittedAt: timestamp,\n    updatedAt: timestamp,\n  };\n  try {\n    console.log('Submitting candidate');\n    const [data] = await pool.query('INSERT into candidates SET ?', candidate);\n    console.log(data);\n    return {\n      statusCode: 200,\n      body: JSON.stringify({\n        message: \\`Sucessfully submitted candidate with email \\${email}\\`,\n        candidateId: data.insertedId,\n      }),\n    };\n  } catch (err) {\n    console.log(err);\n    return {\n      statusCode: 500,\n      body: JSON.stringify({\n        message: \\`Unable to submit candidate with email \\${email}\\`,\n      }),\n    };\n  }\n};`, `42617788855833805000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token string\">'use strict'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> uuid <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'uuid'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> mysql <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'mysql2'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// init mysql connection</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">initMysqlPool</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> <span class=\"token constant\">DB_HOST</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">DB_PORT</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">DB_DATABASE</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">DB_USER</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">DB_PASSWORD</span> <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">const</span> promisePool <span class=\"token operator\">=</span> mysql\n    <span class=\"token punctuation\">.</span><span class=\"token function\">createPool</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      host<span class=\"token punctuation\">:</span> <span class=\"token constant\">DB_HOST</span><span class=\"token punctuation\">,</span>\n      user<span class=\"token punctuation\">:</span> <span class=\"token constant\">DB_USER</span><span class=\"token punctuation\">,</span>\n      port<span class=\"token punctuation\">:</span> <span class=\"token constant\">DB_PORT</span><span class=\"token punctuation\">,</span>\n      password<span class=\"token punctuation\">:</span> <span class=\"token constant\">DB_PASSWORD</span><span class=\"token punctuation\">,</span>\n      database<span class=\"token punctuation\">:</span> <span class=\"token constant\">DB_DATABASE</span><span class=\"token punctuation\">,</span>\n      connectionLimit<span class=\"token punctuation\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">promise</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  promisePool<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span>\n    <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">CREATE TABLE IF NOT EXISTS candidates (\n    id          VARCHAR(64)        NOT NULL,\n    fullname    TEXT          NOT NULL,\n    email       VARCHAR(64)      NOT NULL,\n    experience  INT UNSIGNED  NOT NULL,\n    submittedAt VARCHAR(64)      NOT NULL,\n    updatedAt   VARCHAR(64)      NOT NULL\n  );</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">return</span> promisePool<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> pool <span class=\"token operator\">=</span> <span class=\"token function\">initMysqlPool</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nmodule<span class=\"token punctuation\">.</span>exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">submit</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">,</span> callback</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> requestBody <span class=\"token operator\">=</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> fullname <span class=\"token operator\">=</span> requestBody<span class=\"token punctuation\">.</span>fullname<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> email <span class=\"token operator\">=</span> requestBody<span class=\"token punctuation\">.</span>email<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> experience <span class=\"token operator\">=</span> requestBody<span class=\"token punctuation\">.</span>experience<span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token keyword\">typeof</span> fullname <span class=\"token operator\">!==</span> <span class=\"token string\">'string'</span> <span class=\"token operator\">||</span>\n    <span class=\"token keyword\">typeof</span> email <span class=\"token operator\">!==</span> <span class=\"token string\">'string'</span> <span class=\"token operator\">||</span>\n    <span class=\"token keyword\">typeof</span> experience <span class=\"token operator\">!==</span> <span class=\"token string\">'number'</span>\n  <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Validation Failed'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span>\n      <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Couldn't submit candidate because of validation errors.\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> timestamp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getTime</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> candidate <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    id<span class=\"token punctuation\">:</span> uuid<span class=\"token punctuation\">.</span><span class=\"token function\">v4</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    fullname<span class=\"token punctuation\">:</span> fullname<span class=\"token punctuation\">,</span>\n    email<span class=\"token punctuation\">:</span> email<span class=\"token punctuation\">,</span>\n    experience<span class=\"token punctuation\">:</span> experience<span class=\"token punctuation\">,</span>\n    submittedAt<span class=\"token punctuation\">:</span> timestamp<span class=\"token punctuation\">,</span>\n    updatedAt<span class=\"token punctuation\">:</span> timestamp<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Submitting candidate'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>data<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> pool<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span><span class=\"token string\">'INSERT into candidates SET ?'</span><span class=\"token punctuation\">,</span> candidate<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n      statusCode<span class=\"token punctuation\">:</span> <span class=\"token number\">200</span><span class=\"token punctuation\">,</span>\n      body<span class=\"token punctuation\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        message<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Sucessfully submitted candidate with email </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>email<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n        candidateId<span class=\"token punctuation\">:</span> data<span class=\"token punctuation\">.</span>insertedId<span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n      statusCode<span class=\"token punctuation\">:</span> <span class=\"token number\">500</span><span class=\"token punctuation\">,</span>\n      body<span class=\"token punctuation\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        message<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Unable to submit candidate with email </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>email<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>现在，可以执行部署了：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ serverless deploy -v</code></pre></div>\n<p>这将创建数据表。</p>\n<p>要测试 API，可以再次使用 cURL</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ curl -H &quot;Content-Type: application/json&quot; -X POST -d &#39;{&quot;fullname&quot;:&quot;Shekhar Gulati&quot;,&quot;email&quot;: &quot;shekhargulati84@gmail.com&quot;, &quot;experience&quot;:12}&#39; https://service-6qkg1mbu-1251556596.gz.apigw.tencentcs.com/release/candidate-dev-candidateSubmission</code></pre></div>\n<p>您将从 API 收到如下响应：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  &quot;message&quot;: &quot;Sucessfully submitted candidate with email shekhargulati84@gmail.com&quot;,\n  &quot;candidateId&quot;: &quot;5343f0c0-f773-11e6-84ed-7bf29f824f23&quot;\n}</code></pre></div>\n<h2 id=\"step-4：获取所有候选人\"><a href=\"#step-4%EF%BC%9A%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E5%80%99%E9%80%89%E4%BA%BA\" aria-label=\"step 4：获取所有候选人 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 4：获取所有候选人</h2>\n<p>在 <code class=\"language-text\">serverless.yml</code> 里定义一个新函数：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"24612852854086988000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`listCandidates:\n  handler: candidate.list\n  description: List all candidates\n  events:\n    - apigw:\n        name: listApi\n        parameters:\n          stageName: release\n          serviceId: service-6qkg1mbu\n          httpMethod: GET`, `24612852854086988000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">listCandidates</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> candidate.list\n  <span class=\"token key atrule\">description</span><span class=\"token punctuation\">:</span> List all candidates\n  <span class=\"token key atrule\">events</span><span class=\"token punctuation\">:</span>\n    <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">apigw</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> listApi\n        <span class=\"token key atrule\">parameters</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">stageName</span><span class=\"token punctuation\">:</span> release\n          <span class=\"token key atrule\">serviceId</span><span class=\"token punctuation\">:</span> service<span class=\"token punctuation\">-</span>6qkg1mbu\n          <span class=\"token key atrule\">httpMethod</span><span class=\"token punctuation\">:</span> GET</code></pre></div>\n<p>在 <code class=\"language-text\">api/candidate.js</code> 里创建新功能：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"91685788666803500000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`module.exports.list = async (event, context, callback) => {\n  console.log('Scanning Candidate table.');\n  try {\n    const [data] = await pool.query('select * from candidates');\n    return {\n      statusCode: 200,\n      body: JSON.stringify({\n        candidates: data,\n      }),\n    };\n  } catch (e) {\n    console.log(e);\n    return {\n      statusCode: 500,\n      body: JSON.stringify({\n        message: \\`Unable to get candidates\\`,\n      }),\n    };\n  }\n};`, `91685788666803500000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">module<span class=\"token punctuation\">.</span>exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">list</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">,</span> callback</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Scanning Candidate table.'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>data<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> pool<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span><span class=\"token string\">'select * from candidates'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n      statusCode<span class=\"token punctuation\">:</span> <span class=\"token number\">200</span><span class=\"token punctuation\">,</span>\n      body<span class=\"token punctuation\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        candidates<span class=\"token punctuation\">:</span> data<span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n      statusCode<span class=\"token punctuation\">:</span> <span class=\"token number\">500</span><span class=\"token punctuation\">,</span>\n      body<span class=\"token punctuation\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        message<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Unable to get candidates</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>再次执行部署操作：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">$ sls deploy</code></pre></div>\n<p>部署成功后，您将能够使用 cURL 来测试 API。</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">curl https://service-6qkg1mbu-1251556596.gz.apigw.tencentcs.com/release/candidate-dev-listCandidates\n{&quot;experience&quot;:12,&quot;id&quot;:&quot;5343f0c0-f773-11e6-84ed-7bf29f824f23&quot;,&quot;email&quot;:&quot;shekhargulati84@gmail.com&quot;,&quot;fullname&quot;:&quot;Shekhar Gulati&quot;,&quot;submittedAt&quot;:1487598537164,&quot;updatedAt&quot;:1487598537164}</code></pre></div>\n<h2 id=\"step-5：按照-id-来获取候选人的详细信息\"><a href=\"#step-5%EF%BC%9A%E6%8C%89%E7%85%A7-id-%E6%9D%A5%E8%8E%B7%E5%8F%96%E5%80%99%E9%80%89%E4%BA%BA%E7%9A%84%E8%AF%A6%E7%BB%86%E4%BF%A1%E6%81%AF\" aria-label=\"step 5：按照 id 来获取候选人的详细信息 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 5：按照 ID 来获取候选人的详细信息</h2>\n<p>在 <code class=\"language-text\">serverless.yml</code> 里定义一个新函数：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"94320639721860280000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`  candidateDetails:\n    handler: candidate.get\n    events:\n      - apigw:\n          name: detailApi\n          parameters:\n            stageName: release\n            serviceId:\n            httpMethod: GET`, `94320639721860280000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\">  <span class=\"token key atrule\">candidateDetails</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> candidate.get\n    <span class=\"token key atrule\">events</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">apigw</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> detailApi\n          <span class=\"token key atrule\">parameters</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">stageName</span><span class=\"token punctuation\">:</span> release\n            <span class=\"token key atrule\">serviceId</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">httpMethod</span><span class=\"token punctuation\">:</span> GET</code></pre></div>\n<p>在 <code class=\"language-text\">api/candidate.js</code> 里定义一个新功能：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"77387407414197780000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`module.exports.get = async (event, context, callback) => {\n  try {\n    const id = event.pathParameters.id;\n    const [row] = await pool.query('SELECT * FROM candidates WHERE id = ?', [\n      id,\n    ]);\n    callback(null, row);\n  } catch (e) {\n    console.log(e);\n    callback(null, {\n      statusCode: 500,\n      body: JSON.stringify({\n        message: \\`Unable to get candidate with id \\${id}\\`,\n      }),\n    });\n  }\n};`, `77387407414197780000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">module<span class=\"token punctuation\">.</span>exports<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">get</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">,</span> callback</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> id <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>pathParameters<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>row<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> pool<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span><span class=\"token string\">'SELECT * FROM candidates WHERE id = ?'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>\n      id<span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> row<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n      statusCode<span class=\"token punctuation\">:</span> <span class=\"token number\">500</span><span class=\"token punctuation\">,</span>\n      body<span class=\"token punctuation\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        message<span class=\"token punctuation\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Unable to get candidate with id </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>使用 cURL 测试 API：</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">curl https://05ccffiraa.execute-api.us-east-1.amazonaws.com/dev/candidates/5343f0c0-f773-11e6-84ed-7bf29f824f23\n{&quot;experience&quot;:12,&quot;id&quot;:&quot;5343f0c0-f773-11e6-84ed-7bf29f824f23&quot;,&quot;email&quot;:&quot;shekhargulati84@gmail.com&quot;,&quot;fullname&quot;:&quot;Shekhar Gulati&quot;,&quot;submittedAt&quot;:1487598537164,&quot;updatedAt&quot;:1487598537164}</code></pre></div>\n<h2 id=\"小结\"><a href=\"#%E5%B0%8F%E7%BB%93\" aria-label=\"小结 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>小结</h2>\n<p>至此，本文已经完整地展示了如何通过  <a href=\"https://github.com/serverless/serverless\">Serverless Framework</a> 来创建 REST API，源码下载：<a href=\"https://github.com/yugasun/tencent-serverless-demo/tree/master/serverless-mysql\">Serverless With Mysql</a>。</p>\n<blockquote>\n<p><strong>传送门：</strong></p>\n<ul>\n<li>GitHub: <a href=\"https://github.com/serverless/serverless/blob/master/README_CN.md\">github.com/serverless</a> </li>\n<li>官网：<a href=\"https://serverless.com/\">serverless.com</a></li>\n</ul>\n</blockquote>\n<p>欢迎访问：<a href=\"https://serverlesscloud.cn/\">Serverless 中文网</a>，您可以在 <a href=\"https://serverlesscloud.cn/best-practice\">最佳实践</a> 里体验更多关于 Serverless 应用的开发！</p>","tableOfContents":"<ul>\n<li><a href=\"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/#%E5%BA%94%E7%94%A8%EF%BC%9Aserverless-%E7%BC%96%E7%A8%8B%E9%9D%A2%E8%AF%95%E8%AF%84%E4%BC%B0%E5%99%A8\">应用：Serverless 编程面试评估器</a></li>\n<li><a href=\"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/#%E5%8A%A8%E6%89%8B%E5%87%86%E5%A4%87\">动手准备</a></li>\n<li><a href=\"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/#step-1%EF%BC%9A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA-nodejs-%E6%97%A0%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%A1%B9%E7%9B%AE\">Step 1：创建一个 Node.js 无服务器项目</a></li>\n<li><a href=\"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/#step-2%EF%BC%9A%E5%88%9B%E5%BB%BA%E7%94%A8%E4%BA%8E%E6%8F%90%E4%BA%A4%E5%80%99%E9%80%89%E4%BA%BA%E7%9A%84-rest-%E8%B5%84%E6%BA%90\">Step 2：创建用于提交候选人的 REST 资源</a></li>\n<li><a href=\"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/#step-3%EF%BC%9A%E5%B0%86%E6%95%B0%E6%8D%AE%E4%BF%9D%E5%AD%98%E5%88%B0%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93-mysql-%E4%B8%8A\">Step 3：将数据保存到云数据库 MySQL 上</a></li>\n<li><a href=\"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/#step-4%EF%BC%9A%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E5%80%99%E9%80%89%E4%BA%BA\">Step 4：获取所有候选人</a></li>\n<li><a href=\"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/#step-5%EF%BC%9A%E6%8C%89%E7%85%A7-id-%E6%9D%A5%E8%8E%B7%E5%8F%96%E5%80%99%E9%80%89%E4%BA%BA%E7%9A%84%E8%AF%A6%E7%BB%86%E4%BF%A1%E6%81%AF\">Step 5：按照 ID 来获取候选人的详细信息</a></li>\n<li><a href=\"/blog/2019-12-17-node-rest-api-with-serverless-scf-and-mongodb/#%E5%B0%8F%E7%BB%93\">小结</a></li>\n</ul>"},"previousBlog":{"id":"ddfeb84b-7b61-5d10-beea-74eae6fcd9aa","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020327/1585306882643-9.jpg","authors":["serverless 社区"],"categories":["meetup"],"date":"2019-12-20T00:00:00.000Z","title":"Serverless 前端工程化落地与实践 - GMTC 大会","description":"腾讯 Serverless 技术专家王俊杰在 GMTC 全球大前端技术大会分享了 Serverless 前端工程化落地与实践","authorslink":["https://serverlesscloud.cn"],"translators":null,"translatorslink":null,"tags":["serverless","Meetup"],"keywords":"Serverless 全局变量组件,Serverless 单独部署组件,Serverless Component","outdated":null},"wordCount":{"words":78,"sentences":27,"paragraphs":27},"fileAbsolutePath":"/opt/build/repo/content/blog/2019-12-20-gmtc.md","fields":{"slug":"/blog/2019-12-20-gmtc/","keywords":["serverless","云函数","Serverless","前端","serverless","落地","开发"]}},"nextBlog":{"id":"1e54dd30-fe20-593b-952b-869b890aced3","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020114/1579000616928-HEAD.png","authors":["Anycodes"],"categories":["guides-and-tutorials"],"date":"2019-12-10T00:00:00.000Z","title":"Serverless 的资源评估与成本探索","description":"本文介绍了使用 Serverless 架构布局业务时，需要关注的资源和费用","authorslink":["https://www.zhihu.com/people/liuyu-43-97"],"translators":null,"translatorslink":null,"tags":["资源成本","Serverless"],"keywords":"Serverless 架构,Serverless 布局业务,Serverless 资源评估","outdated":null},"wordCount":{"words":341,"sentences":66,"paragraphs":66},"fileAbsolutePath":"/opt/build/repo/content/blog/2019-12-10-resource-cost.md","fields":{"slug":"/blog/2019-12-10-resource-cost/","keywords":["serverless","云函数","内存","serverlesscloud"]}},"recommendBlogs":{"edges":[{"node":{"id":"665f9ce2-4451-59fd-bf98-1861789d3b3b","frontmatter":{"thumbnail":"https://s3-us-west-2.amazonaws.com/assets.blog.serverless.com/Serverless_logo.png","authors":["AndreaPasswater"],"categories":["guides-and-tutorials","engineering-culture"],"date":"2018-03-19T00:00:00.000Z","title":"如何为无服务器开放源代码项目做贡献","description":"想要为无服务器开放源代码项目做贡献？您可以遵循下面的指南。","authorslink":null,"translators":null,"translatorslink":null,"tags":null,"keywords":null,"outdated":null},"wordCount":{"words":96,"sentences":36,"paragraphs":36},"fileAbsolutePath":"/opt/build/repo/content/blog/2018-03-19-how-contribute-to-serverless-open-source.md","fields":{"slug":"/blog/2018-03-19-how-contribute-to-serverless-open-source/","keywords":["serverless","无服务器","serverless","github","插件","服务器","贡献","示例","blog","contribute"]}}},{"node":{"id":"a3e92579-65c3-5159-937c-32d18c5df7d7","frontmatter":{"thumbnail":"https://s3-us-west-2.amazonaws.com/assets.blog.serverless.com/why-not/why-not-header.png","authors":["AndreaPasswater"],"categories":["guides-and-tutorials","operations-and-observability","engineering-culture"],"date":"2018-03-21T00:00:00.000Z","title":"不适合选择无服务器的情境及原因","description":"无服务器既有优点也有缺点。那么，哪些情境下不适合选择无服务器？原因又是什么呢？","authorslink":null,"translators":null,"translatorslink":null,"tags":null,"keywords":null,"outdated":null},"wordCount":{"words":163,"sentences":43,"paragraphs":43},"fileAbsolutePath":"/opt/build/repo/content/blog/2018-03-21-when-why-not-use-serverless.md","fields":{"slug":"/blog/2018-03-21-when-why-not-use-serverless/","keywords":["faas","react","serverless","spa","无服务器","无服务器函数","无服务器架构","无服务器开发","服务器","twitter","serverless","blockquote","lang","script","en"]}}},{"node":{"id":"6a16520b-7886-582e-9182-64e50712d486","frontmatter":{"thumbnail":"https://s3-us-west-2.amazonaws.com/assets.blog.serverless.com/vendor+choice/serverless-data-portability.jpg","authors":["NickGottlieb"],"categories":["engineering-culture","guides-and-tutorials"],"date":"2018-06-20T00:00:00.000Z","title":"浅谈无服务器、数据锁定和供应商选择","description":"供应商选择是如今 IT 领导者需要考虑的最重要事项，而这一点可利用数据可移植性来实现。","authorslink":null,"translators":null,"translatorslink":null,"tags":null,"keywords":null,"outdated":null},"wordCount":{"words":205,"sentences":33,"paragraphs":33},"fileAbsolutePath":"/opt/build/repo/content/blog/2018-06-20-data-lockin-vendor-choice-portability.md","fields":{"slug":"/blog/2018-06-20-data-lockin-vendor-choice-portability/","keywords":["go","serverless","无服务器","无服务器架构","供应商","serverless","开发人员","数据","锁定","选择","服务"]}}},{"node":{"id":"94741abb-10ba-5db1-9756-cd1d573473fa","frontmatter":{"thumbnail":"https://s3-us-west-2.amazonaws.com/assets.blog.serverless.com/webstorm-ide/streamline-webstorm-serverless2.jpg","authors":["EslamHefnawy"],"categories":["guides-and-tutorials","engineering-culture"],"date":"2018-08-15T00:00:00.000Z","title":"如何使用 WebStorm 简化无服务器工作流程","description":"在本文中，我将和您分享如何使用 WebStorm 进行无服务器特定的 IDE 设置以及如何利用它来极大地加快无服务器工作流程。","authorslink":null,"translators":null,"translatorslink":null,"tags":null,"keywords":null,"outdated":null},"wordCount":{"words":234,"sentences":54,"paragraphs":54},"fileAbsolutePath":"/opt/build/repo/content/blog/2018-08-15-streamline-serverless-workflow-webstorm.md","fields":{"slug":"/blog/2018-08-15-streamline-serverless-workflow-webstorm/","keywords":["nodejs","serverless","无服务器","无服务器开发","serverless","WebStorm","webstorm","服务器","blog","assets"]}}},{"node":{"id":"713a0563-4bf9-5721-bacb-3b4ef609fe4a","frontmatter":{"thumbnail":"https://s3-us-west-2.amazonaws.com/assets.blog.serverless.com/camp-fire/camp-fire-housing-thumb.jpg","authors":["EricWyne"],"categories":["guides-and-tutorials","user-stories"],"date":"2018-12-05T00:00:00.000Z","title":"Serverless Twitter 机器人帮助为坎普山火受灾者安置住房","description":"加利福尼亚州的坎普山火致使数千人流离失所，为此，我构建了一个简单的 Serverless Twitter 机器人来帮助将受灾者安置在临时住房！","authorslink":["https://serverless.com/author/ericwyne/"],"translators":["Aceyclee"],"translatorslink":["zhihu.com/people/Aceyclee"],"tags":null,"keywords":null,"outdated":null},"wordCount":{"words":157,"sentences":26,"paragraphs":26},"fileAbsolutePath":"/opt/build/repo/content/blog/2018-12-05-serverless-twitter-camp-fire.md","fields":{"slug":"/blog/2018-12-05-serverless-twitter-camp-fire/","keywords":["serverless","无服务器","云函数","Serverless","org","住房","Twitter","函数","受灾","机器人","山火"]}}},{"node":{"id":"17c972d9-0583-51f6-9d5d-c2ba5f21b6a3","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/20191227/1577409288454-v2-577c2b21d600e3ea07f156f3e9d2d6b8_1200x500.jpg","authors":["Alfred Huang"],"categories":["guides-and-tutorials"],"date":"2019-08-21T00:00:00.000Z","title":"Serverless 的运行原理与组件架构","description":"本文重点探讨下开发者使用 Serverless 时经常遇到的一些问题，以及如何解决","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["运行原理","serverless"],"keywords":"Serverless 运行原理,Serverless 组件架构","outdated":null},"wordCount":{"words":236,"sentences":33,"paragraphs":33},"fileAbsolutePath":"/opt/build/repo/content/blog/2019-08-21-serverless-operation-architecture.md","fields":{"slug":"/blog/2019-08-21-serverless-operation-architecture/","keywords":["koa","serverless","云函数","Serverless","用户","函数","请求","实例","形态","业务","serverlesscloud"]}}},{"node":{"id":"ae4fd2f8-515c-5aec-b584-38427ef33f7e","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020114/1578989800047-part-00492-780.jpg","authors":["Anycodes"],"categories":["guides-and-tutorials","user-stories"],"date":"2019-09-16T00:00:00.000Z","title":"突破传统 OJ 瓶颈，「判题姬」接入云函数","description":"通过 Serverless 实现在线编程","authorslink":["https://www.zhihu.com/people/liuyu-43-97"],"translators":null,"translatorslink":null,"tags":["在线编程","云函数"],"keywords":"Serverless 在线编程,Serverless OJ","outdated":null},"wordCount":{"words":169,"sentences":30,"paragraphs":30},"fileAbsolutePath":"/opt/build/repo/content/blog/2019-09-16-online-Judge.md","fields":{"slug":"/blog/2019-09-16-online-Judge/","keywords":["python","serverless","云函数","代码","函数","serverless"]}}},{"node":{"id":"545ab3d2-e14e-5cc2-8548-0e863eac942b","frontmatter":{"thumbnail":"https://s3-us-west-2.amazonaws.com/assets.blog.serverless.com/2019-10-deployment-best-practices/safeguard-header.png","authors":["FernandoMedinaCorey"],"categories":["guides-and-tutorials"],"date":"2019-10-14T00:00:00.000Z","title":"无服务器部署最佳实践","description":"了解部署无服务器应用时的一些最佳实践。","authorslink":null,"translators":null,"translatorslink":null,"tags":null,"keywords":null,"outdated":null},"wordCount":{"words":221,"sentences":46,"paragraphs":46},"fileAbsolutePath":"/opt/build/repo/content/blog/2019-10-14-serverless-deployment-best-practices.md","fields":{"slug":"/blog/2019-10-14-serverless-deployment-best-practices/","keywords":["serverless","无服务器","serverless","部署","服务器","开发人员","应用","安全措施","使用","函数"]}}}],"totalCount":31}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"8d3e0a32-3028-5f67-b38e-9088a83b37ab","previousBlogId":"ddfeb84b-7b61-5d10-beea-74eae6fcd9aa","nextBlogId":"1e54dd30-fe20-593b-952b-869b890aced3","categories":["guides-and-tutorials"]}}}