【BTP】 使用Node.js和PostgreSQL创建简单的应用程序(1)准备篇

首先

前不久,我写了以下的文章。
【CAP】将CAP部署到BTP的PostgreSQL数据库。

使用cds-pg和cds-dbm,可以将在CAP中创建的CDS模型部署到PostgreSQL并使用。
CAP会自动处理表和视图的注册及CRUD操作,开发者无需关注这些工作。然而,我也希望了解一下如果不使用CAP,需要做什么。

因为有以下示例项目(教程),所以我将参考它创建一个简单的Node.js应用程序并确认步骤。SAP-samples/cloud-cf-helloworld-nodejs

<系列目录>

    • 【BTP】Node.jsとPostgreSQLでシンプルなアプリケーションを作成(1)準備編

 

    • 【BTP】Node.jsとPostgreSQLでシンプルなアプリケーションを作成(2)CRUD処理編

 

    • 【BTP】Node.jsとPostgreSQLでシンプルなアプリケーションを作成(3)Approuter編

 

    【BTP】Node.jsとPostgreSQLでシンプルなアプリケーションを作成(4)UI編

源代码存储在GitHub上,请参考文章。

这篇文章的目标是什么?

本次我们将作为准备篇,创建以下状态。

    • Node.jsアプリケーションとBTPのPostgreSQLのサービスインスタンスがバインドされている

 

    • PostgreSQLにアプリケーションで使うテーブルが登録されている

 

    Node.jsアプリケーションからBTPのPostgreSQLに接続できる

##步骤

    1. 将 Node.js 应用程序和 PostgreSQL 服务实例进行绑定

 

    1. 在 PostgreSQL 中注册表

 

    从 Node.js 应用程序连接到 PostgreSQL

将Node.js应用程序与PostgreSQL服务实例绑定。

1. 在中国,注册一个PostgreSQL的服务实例。

使用下面的命令将服务实例注册。

cf create-service postgresql-db trial <サービスインスタンス名>

在试用环境中,只能创建一个PostgreSQL的服务实例,所以可以重复使用现有的服务实例。我使用了已注册的服务实例cap-posgre-sample-db。

1.2. 创建Node.js项目

创建一个新的文件夹用于新项目,并在其下创建一个名为srv的文件夹。

node-postgres-sample
 └ srv

进入srv文件夹并创建package.json文件。

cd node-postgres-sample/srv
npm init --yes

1.3. 安装依赖。

将以下四个软件包进行安装。

npm i express body-parser pg-promise @sap/xsenv

pg-promiseはPostgreSQLに接続したり、クエリを実行したりするのに使用します。

@sap/xsenvはアプリケーションの環境変数にアクセスするのに使用します。

在package.json中添加start脚本,并设为以下状态。

{
  "name": "node-postgres-sample",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "@sap/xsenv": "^3.1.0",
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "pg-promise": "^10.10.2"
  }
}

创建 server.js 文件。

创建一个server.js文件。目前还没有与数据库的连接。

'use strict';

const express = require('express')
const bodyParser = require('body-parser')

var _db = undefined
const app = express()

app.use(bodyParser.json())

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

var PORT = process.env.PORT || 8088
var server = app.listen(PORT, function() {
    const host = server.address().address
    const port = server.address().port
    console.log(`Example app listening at http://${host}:${port}`)    
})
image.png

创建1.5个mta.yaml文件

我們將在專案的根目錄下創建mta.yaml文件。

_schema-version: '3.1'
ID: node-postgres-sample
version: 1.0.0

modules:
 - name: node-postgres-sample-srv
   type: nodejs
   path: srv
   provides:
    - name: srv-api
      properties:
        srv-url: ${default-url}
   build-parameters:
     ignore: ["node_modules/"]        
   requires:
    - name: cap-posgre-sample-db
    
resources:
  - name: cap-posgre-sample-db
    parameters:
      service: postgresql-db
      service-plan: trial
      skip-service-updates:
        parameters: true
    type: org.cloudfoundry.existing-service   #登録済サービスインスタンスのため、existing-serviceとする

目前为止,该项目的结构如下。

node-postgres-sample
 └ srv
     |- package.json
     └  server.js
 └ mta.yaml

1.6 将应用部署到 Cloud Foundry

在项目的根目录下执行以下命令,将其部署到Cloud Foundry。

mbt build
cf deploy mta_archives/node-postgres-sample_1.0.0.mtar

2. 将表格注册到PostgreSQL数据库。

在应用程序中注册要在PostgreSQL中使用的表格。为此,通过SSH连接到PostgreSQL,使用命令行进行操作。有关工具安装和连接到PostgreSQL的方法,请参考这篇文章。

为了连接到PostgreSQL服务实例,需要一个充当主机的应用程序。为此,我们先执行了步骤1。本次,主机应用程序将是node-postgres-sample-srv。

2.1. 注册桌子

执行以下SQL语句,将数据存入products表中。

CREATE TABLE products (
id serial PRIMARY KEY,
name varchar(100),
price integer
);

2.2. 将数据登记到表格中

执行以下SQL语句,将数据插入到表中。
由于id是自动递增的序列,所以不需要指定。

INSERT INTO products(name, price) VALUES ('banana', 100);

确认已经注册了录音记录。

SELECT * FROM products;
 id |  name  | price
----+--------+-------
  1 | banana |   100
(1 行)

从Node.js应用程序连接到PostgreSQL。

请在srv文件夹中创建一个名为db-conn.js的文件。在此文件中编写用于连接数据库的代码。
项目的结构如下所示。

node-postgres-sample
 └ srv
     |- package.json
     |- db-conn.js
     └  server.js
 └ mta.yaml
'use strict'
const xsenv = require('@sap/xsenv')

function getConfig () {
    var config = {}
    if (process.env.VCAP_SERVICES) {
        config = {
            connectionString: xsenv.cfServiceCredentials('cap-posgre-sample-db').uri,
            ssl: { rejectUnauthorized: false }
        }
    } else {
        console.log('running locally is not supported')
    }
    return config;
}
        
function getDB (cb) {
    let pgp = require('pg-promise')({
        // Initialization Options
    })
    var db = pgp(getConfig())
    let sql = `SELECT id FROM products WHERE id = 1;`
    db.query(sql)
    .then((result) => {
        console.log('database initialized', result)
        cb(null, db)
        return
    })
    .catch((err) => {
        console.log(err)
        cb(err, null)
        return
    })
}

module.exports  = {
    getDB: getDB
}

我們也會修改server.js,使其在啟動時檢查與數據庫的連接。

'use strict';

const express = require('express')
const bodyParser = require('body-parser')

const dbConn = require('./db-conn')

var _db = undefined
const app = express()

app.use(bodyParser.json())

app.get("/", function (req, res) {
    res.send("Hello!")
})

function setDBCallback(error, db) {
    if (error !== null) {
        console.log('error when fetching the DB connection ' + JSON.stringify(error))
        return
    }
    _db = db;
}

var PORT = process.env.PORT || 8088
var server = app.listen(PORT, function() {
    const host = server.address().address
    const port = server.address().port
    console.log(`Example app listening at http://${server}:${port}`)

    dbConn.getDB(setDBCallback);
})

我們將進行構建和部署。

在部署时,通过运行 “cf logs node-postgres-sample-srv” 命令来查看应用程序的日志。如果如下所示能够无错误地启动,则说明与数据库的连接顺利建立。

   2021-05-27T15:27:58.72+0900 [CELL/0] OUT Downloaded droplet (22.9M)
   2021-05-27T15:27:58.72+0900 [CELL/0] OUT Starting health monitoring of container
   2021-05-27T15:27:59.71+0900 [APP/PROC/WEB/0] OUT > node-postgres-sample@1.0.0 start /home/vcap/app
   2021-05-27T15:27:59.71+0900 [APP/PROC/WEB/0] OUT > node server.js
   2021-05-27T15:27:59.95+0900 [APP/PROC/WEB/0] OUT Example app listening at http://[object Object]:8080
   2021-05-27T15:28:00.09+0900 [APP/PROC/WEB/0] OUT database initialized [ { id: 1 } ]
   2021-05-27T15:28:01.59+0900 [CELL/0] OUT Container became healthy

可以在下面的行中确认数据是否已获取。

 2021-05-27T15:28:00.09+0900 [APP/PROC/WEB/0] OUT database initialized [ { id: 1 } ]

(仅提供一种选项)关于连接的反复尝试和错误

在我所参考的源代码中,连接到数据库的处理如下所示。

function returnUriToDB() {
    var uri = '';
    if (process.env.VCAP_SERVICES) {
        // running in cloud
        uri = xsenv.cfServiceCredentials('sapcpcfhw-db').uri;
    } else {
        console.log('running locally is not supported');
    }
    return uri;
}


function getDB(cb) {
    let pgp = require('pg-promise')({
        // Initialization Options
    });
    var db = pgp(returnUriToDB());
    ...
}
image.png

在参考本QA的情况下,我在连接URL上添加了?ssl=true,错误的内容发生了变化。

uri = xsenv.cfServiceCredentials('cap-posgre-sample-db').uri + `?ssl=true`
image.png
        config = {
            connectionString: xsenv.cfServiceCredentials('cap-posgre-sample-db').uri,
            ssl: { rejectUnauthorized: false }
        }

总结

在这篇文章中,我们进行了以下实施措施。

    • Node.jsアプリケーションとPostgreSQLのサービスインスタンスをバインド

 

    • PostgreSQLにテーブルを登録

 

    Node.jsアプリケーションからPostgreSQLに接続

如果不使用CAP,我们知道了为了连接数据库必须要做什么。下一次我们想要实现对于表的CRUD操作。

请参考

    SAP-samples/cloud-cf-helloworld-nodejs/Chapter 2: Node.js RESTful API persists data in PostgreSQL DB
bannerAds