使用AWS SimpleDB和Node.js构建REST API

SimpleDB是Amazon Web Services(AWS)提供的远程数据库。 数据存储的领域通常根据SQL语言的使用(或不使用)分为SQL和NoSQL。 NoSQL数据存储通常基于更简单的键/值设置。 SimpleDB跨越了这一行-它是键/值存储,它也可以使用SQL的变体进行检索。 大多数SQL语言都是基于对数据的行和列进行布局的模式,但是SimpleDB是一种无模式的数据库,可实现非常灵活的数据存储。

在SimpleDB数据库模型中,您具有项目,属性和值。 数据库中的每一行都是一个项目 ,可以通过唯一且可分配的项目名称进行标识。 每个项目最多可以具有256对属性 。 SimpleDB的意外方面是,一个属性每个项目可以具有多个对。 我认为考虑SimpleDB的最佳方法是考虑电子表格,但不是每个列/行的交集代表一个值,而是代表一个值数组。

显示项目名称属性值关系的网格

此图表表示存储在SimpleDB 域中的两项 术语“ 域”类似于其他数据库中的“表”。

第一列是项目名称,这是唯一只有一个值且可以将其视为唯一索引列的唯一列。

其他四列( 宠物汽车家具电话 )代表了该域中当前的属性-您不仅限于此,因此每个项目都可以具有一组完全唯一的属性。 在此数据中,项目personInventory1上的属性pets具有三对。 以JSON表示,看起来会像这样:

{ "Name" : "pets", "Value" : "dog" }, 
{ "Name" : "pets", "Value" : "cat" }, 
{ "Name" : "pets", "Value" : "fish" }

另一方面,项目personInventory2只有一对:

{ "Name" : "pets", "Value" : "cat" }

虽然不必为每个项目都提供相同的属性,但是您确实需要至少提供一对。 这意味着您不能拥有“空”物品。 每个属性的值上限为1kb,因此,由于1kb的值限制和256对限制,因此每个项目在功能上都限制为256kb。

SimpleDB是分布式的,在设计应用程序时,您需要了解并牢记一些独特的特征。 成为分布式数据库意味着一整组计算机将响应您的请求,并且您的数据将在这些服务器中复制。 这种分布对您的程序是完全透明的,但确实会引入一致性问题的可能性-您的数据不能保证最初会出现在所有服务器上。

不要惊慌:它并没有听起来那么糟糕,有几个原因。 使用SimpleDB,并不能保证一致性,但是通常情况下,一致性很好,并且根据我的经验很快可以到达所有节点。 围绕它进行设计也并不困难-通常,您会尝试避免立即读取刚刚编写的记录。 最后,SimpleDB可以选择执行一致的读取,但是读取速度较慢,并且可能消耗更多资源。 如果您的应用程序每次都需要一致的读取,则可能需要重新考虑将SimpleDB用作数据存储,但是对于许多应用程序而言,可以围绕它进行设计甚至不用担心。

从好的方面来说,分布式特性还为SimpleDB提供了一些与Node.js环境很好地结合的优点。 由于没有单个服务器来响应您的请求,因此您不必担心服务饱和,并且可以通过向SimpleDB发出许多并行请求来获得良好的性能。 并行和异步请求是Node.js可以轻松处理的事情。

与许多AWS服务不同,没有Amazon提供的用于管理SimpleDB的控制台。 幸运的是,有一个不错的浏览器内置管理控制台,形式为Google Chrome插件SdbNavigator 。 在SdbNavigator中,您可以添加或删除域,插入,更新和删除项目,修改属性以及执行查询。

AWS开发工具包

现在我们已经了解了SimpleDB服务,让我们开始编写REST服务器。 首先,我们需要安装AWS开发工具包。 该SDK不仅处理SimpleDB,而且还处理所有AWS服务,因此您可能已经将其包含在package.json文件中。 要安装SDK,请从命令行运行以下命令:

npm install aws-sdk —-save

要使用SimpleDB,您还需要获取AWS凭证 ,其中包括访问密钥和秘密密钥。 SimpleDB是一种即用即付的服务,但是AWS当前包括对SimpleDB的大量免费津贴。

警告词 :与任何随用随付服务一样,请注意,有可能编写可能导致大笔账单的代码,因此您将需要密切注意使用情况并将凭据保密和安全。

一旦安装了AWS开发工具包并获得了凭证,就需要在代码中设置SimpleDB。 在此示例中,我们将使用存储在主目录中的JSON文件中的AWS凭证。 首先,您需要包括SDK模块,创建一个AWS对象,最后设置您的SimpleDB接口。

var
  aws         = require('aws-sdk'),
  simpledb;

aws.config.loadFromPath(process.env['HOME'] + '/aws.credentials.json');

//We'll use the Northern Virginia datacenter, change the region / endpoint for other datacenters http://docs.aws.amazon.com/general/latest/gr/rande.html#sdb_region
simpledb = new aws.SimpleDB({
  region    : 'US-East',
  endpoint  : 'https://sdb.amazonaws.com'
});

注意,我们正在使用特定的端点和区域。 每个数据中心都是完全独立的,因此,例如,如果在北弗吉尼亚州创建一个名为“ mysuperawesomedata ”的域,则该域将不会复制到圣保罗数据中心也不会出现在圣保罗数据中心中。

使用new aws.SimpleDB创建的SimpleDB对象new aws.SimpleDB是您与SimpleDB进行交互的所有方法的基础。 适用于SimpleDBAWS开发工具包只有几种方法

批处理操作

  • batchDeleteAttributes
  • batchPutAttributes

域名管理与信息

  • createDomain
  • deleteDomain
  • 域元数据
  • listDomains

项目/属性操作

  • deleteAttributes
  • getAttributes
  • putAttributes

查询方式

  • 选择

在本教程中,我们将仅处理项目/属性操纵和查询; 尽管其他类别很有用,但许多应用程序对它们没有任何用处。

测试数据

使用SdbNavigator,在工具中输入访问和安全密钥,选择“美国东部”,然后单击“连接”。

与SdbNavigator的连接UI

成功连接后,让我们创建一个用于测试的域。 单击添加域

通过SdbNavigator添加域

然后输入域名“ sdb-rest-tut”,然后单击“ 确定”

输入新域的名称

现在,您已经创建了域,让我们输入一些测试数据。 单击添加属性,然后添加一个名为“颜色”的属性。 按照惯例,我通常以复数形式命名属性,以反映SimpleDB的多值性质。

向记录添加属性名称

最后,我们将单击“ 添加记录”以创建我们的第一个SimpleDB项。 在ItemName()列中,输入唯一的项目名称。 SdbNavigator的一个怪癖是,默认情况下,它仅对每个项目接受一个值,但这掩盖了一个属性可以包含多个值的事实。 要输入多个值,请单击属性列右边缘的S。

输入唯一的商品名称

在新框中,选择数组以输入多个值。 在“ 值”列中,输入“ red”,然后单击“ 添加值”并输入“ blue”。

输入项目的数据类型

最后,单击更新以将更改保存到此行。

更新项目的数据类型

现在我们已经输入了一些测试数据,让我们从Node发出第一个SimpleDB请求。 我们将只获取域中的所有内容,此时,它仅是一行。

var
  aws         = require('aws-sdk'),
  simpledb;

aws.config.loadFromPath(process.env['HOME'] + '/aws.credentials.json');

simpledb = new aws.SimpleDB({
  region     	: 'US-East',
  endpoint 	: 'https://sdb.amazonaws.com'
});

simpledb.select({
  SelectExpression  : 'select * from `sdb-rest-tut` limit 100'
}, function(err,resp) {
  if (err) {
    console.error(err);
  } else {
    console.log(JSON.stringify(resp,null,' '));
  }
});

响应将被记录到控制台。 这是响应,带有注释以供解释:

{
 "ResponseMetadata": {
  "RequestId": "...",             //Every request made to SimpleDB has a request ID
  "BoxUsage": "0.0000228616"      //This is how your account is charged, as of time of writing US-East region is 14 US cents per hour, so this request costs 0.00032 cents + the transfer cost (if you are currently outside of your free tier)
 },
 "Items": [                       //For a Select, your response will be in the "Items" object property
  {
   "Name": "myfirstitem",         //this is the itemName()
   "Attributes": [                //these are the attribute pairs
    {
     "Name": "colors",            //attribute name
     "Value": "red"               //value - note that every Value is a string, regardless of the contents
    },
    {
     "Name": "colors",            //Since the attribute name is repeated, we can see that `colors` has more than one value
     "Value": "blue"
    }
   ]
  }
 ]
}

REST服务器

由于我们将构建一个将数据存储在SimpleDB中的REST服务器,因此了解REST服务器的功能非常重要。 REST表示RE表象小号大老贸易交接。 REST服务器实际上只是使用HTTP标准机制作为数据接口的服务器。 REST通常用于服务器到服务器的通信,但是您可以通过jQuery或Angular等JavaScript库将REST服务器与客户端一起使用。 但是,通常,最终用户不会直接与REST服务器进行交互。

有趣的是,AWS开发工具包实际上使用REST协议与SimpleDB进行交互,因此将REST服务器创建到另一个REST服务器似乎有些奇怪。 您不想直接使用SimpleDB REST API,因为您需要对请求进行身份验证,这将冒用AWS账户安全的风险。 另外,通过编写服务器,您将能够在数据存储中添加抽象层和验证层,这将使整个应用程序的其余部分更易于处理。

在本文,我们将建立基本CRUD + L功能,即是C reate,R EAD,U PDATE,d elete和L IST。 如果考虑一下,您可以将大多数应用程序分解为CRUD + L。 使用REST,您将使用数量有限的路径和几个HTTP方法或动词来创建直观的API。 大多数开发人员都熟悉一些HTTP动词,即GET和POST,因为它们最常在Web应用程序中使用,但还有其他几个动词。

运作方式 HTTP动词
创造 开机自检
得到
更新资料
删除 删除
清单 得到

注意,Read和List都使用相同的动词。 我们将使用略有不同的路径来区分两者。 我们使用POST表示创建,因为创建不被视为幂等。 幂等意味着多次相同的调用将对用户和您的数据产生相同的结果,因此更新(aka PUT)将被视为幂等。

作为示例,我们将构建一个个人库存服务器-一个数据库来保存您拥有的任何东西。 这是路径的样子:

运作方式 HTTP动词 路径
创造 开机自检 /库存
得到 /库存/ 1234
更新资料 /库存/ 1234
删除 删除 /库存/ 1234
清单 得到 /库存

1234是人员标识符(ID)的占位符-请注意,“创建”和“列表”没有ID。 对于create,将生成ID,并使用列表获取所有名称,因此不需要特定的ID。

构建服务器

首先,让我们安装Node.js HTTP服务器框架Express

npm install express —-save

Express在设置服务器时管理着大多数细节,但是它不包含用于处理HTTP请求正文的任何​​功能,因此我们需要安装另一个模块body-parser ,以使我们能够读取请求正文。

npm install body-parser --save

正文解析器具有几种用于解析HTTP请求正文的选项。 为了提高可读性,我们将使用json()方法,但是切换到另一种方法只是换出bodyParser对象上的方法。 我们只需要在create和update方法上使用bodyParser方法,因此我们可以将其包括在那些特定的路由中。

创造

由于每个SimpleDB itemName需要唯一,因此我们可以为每个新创建的项目自动生成一个新的itemName 。 我们将使用cuid模块,这是一种生成唯一标识符的轻量级方法。

npm install cuid --save

SimpleDB期望属性采用属性名称/值对格式:

[
    { "Name" : "attribute1", "Value" : "value1" },
    { "Name" : "attribute1", "Value" : "value2" },
    { "Name" : "attribute2", "Value" : "value3" },
    { "Name" : "attribute3", "Value" : "value4" }
]

您的服务器当然可以只接受这种格式的值并将其直接传递给SimpleDB,但这与通常如何构造数据是不合常理的,并且很难使用。 我们将使用更直观的数据结构,即对象/值数组:

{
    "attribute1"    : ["value1","value2"],
    "attribute2"    : ["value3","value4"]
}

这是带有创建操作的基于Express的基本服务器:

var
  aws         = require('aws-sdk'),
  bodyParser  = require('body-parser'),
  cuid        = require('cuid'),
  express     = require('express'),
  
  sdbDomain   = 'sdb-rest-tut',
  
  app         = express(),
  simpledb;

aws.config.loadFromPath(process.env['HOME'] + '/aws.credentials.json');
simpledb = new aws.SimpleDB({
  region     	: 'US-East',
  endpoint 	: 'https://sdb.amazonaws.com'
});

//create
app.post(
  '/inventory', 
  bodyParser.json(),
  function(req,res,next) {
    var
      sdbAttributes   = [],
      newItemName     = cuid();
    
    //start with: 
    /*
      { attributeN     : ['value1','value2',..'valueN'] }
    */
    Object.keys(req.body).forEach(function(anAttributeName) {
      req.body[anAttributeName].forEach(function(aValue) {
        sdbAttributes.push({
          Name  : anAttributeName,
          Value : aValue
        });
      });
    });
    //end up with:
    /*
      [ 
        { Name : 'attributeN', Value : 'value1' },
        { Name : 'attributeN', Value : 'value2' },
        ...
        { Name : 'attributeN', Value : 'valueN' },
      ]
    */

    simpledb.putAttributes({
      DomainName    : sdbDomain,
      ItemName      : newItemName,
      Attributes    : sdbAttributes
    }, function(err,awsResp) {
      if (err) { 
        next(err);  //server error to user
      } else {
        res.send({
          itemName  : newItemName 
        });
      }
    });
  }
);


app.listen(3000, function () {
  console.log('SimpleDB-powered REST server started.');
});

让我们启动服务器并尝试一下。 与REST服务器交互的一种好方法是使用cURL工具 。 此工具可让您直接从命令行使用任何动词发出HTTP请求。 要尝试使用REST服务器创建商品,我们需要激活一些其他选项:

curl -H "Content-Type: application/json" -X POST -d '{"pets" : ["dog","cat"], "cars" : ["saab"]}' http://localhost:3000/inventory
选项 目的
-H 在HTTP标题中添加一行
-X 定义将使用的动词
-d 要在HTTP请求正文中发送的数据

运行命令后,您将看到带有新创建的itemName或ID的JSON响应。 如果切换到SdbNavigator,则在查询所有项目时应该会看到新数据。

现在,让我们构建一个基本函数以从SimpleDB中读取项目。 为此,我们不需要执行查询,因为我们将从请求的路径中获取itemName或ID。 我们可以使用该itemName或ID执行getAttributes请求。

如果我们在这里停下来,我们将获得功能齐全但不太友好的数据形式。 让我们将Name / Value数组转换为用于接受数据的相同形式(attribute:值数组)。 为此,我们将需要遍历每个名​​称/值对,并将其添加到每个唯一名称的新数组中。

最后,让我们添加itemName并返回结果。

//Read
app.get('/inventory/:itemID', function(req,res,next) {
  simpledb.getAttributes({
    DomainName    : sdbDomain,
    ItemName      : req.params.itemID   //this gets the value from :itemID in the path
  }, function(err,awsResp) {
    var
      attributes = {};
      
    if (err) { 
      next(err);  //server error to users
    } else {
      awsResp.Attributes.forEach(function(aPair) {
        // if this is the first time we are seeing the aPair.Name, let's add it to the response object, attributes as an array
        if (!attributes[aPair.Name]) { 
          attributes[aPair.Name] = [];
        }
        //push the value into the correct array
        attributes[aPair.Name].push(aPair.Value);
      });
      res.send({
        itemName    : req.params.itemID,
        inventory   : attributes
      });
    }
  });
});

为了测试这一点,我们需要再次使用curl。 尝试用本教程前面的创建项目示例返回的itemName或ID替换[cuid]

curl -D- http://localhost:3000/inventory/[cuid]

请注意,我们正在使用   -D-选项。 这将转储HTTP头,以便我们可以看到响应代码。

REST的另一方面是有意义地使用您的响应代码 。 在当前的例子,如果你提供一个不存在的ID卷曲,上面的服务器会崩溃,因为你想forEach一个不存在的数组。 我们需要考虑到这一点,并返回一个有意义的HTTP响应代码,指示未找到该项目。

为了防止错误,我们应该测试变量awsResp.Attributes的存在。 如果不存在,我们将状态代码设置为404并结束http请求。 如果存在,那么我们可以为响应提供属性。

app.get('/inventory/:itemID', function(req,res,next) {
  simpledb.getAttributes({
    DomainName    : sdbDomain,
    ItemName      : req.params.itemID
  }, function(err,awsResp) {
    var
      attributes = {};
      
    if (err) { 
      next(err);
    } else {
      if (!awsResp.Attributes) {
        //set the status response to 404 because we didn't find any attributes then end it
        res.status(404).end(); 
      } else {
        awsResp.Attributes.forEach(function(aPair) {
          if (!attributes[aPair.Name]) { 
            attributes[aPair.Name] = [];
          }
          
          attributes[aPair.Name].push(aPair.Value);
        });
        res.send({
          itemName    : req.params.itemID,
          inventory   : attributes
        });
      }
    }
  });
});

使用新代码和不存在的ID尝试一下,您将看到服务器返回404。

现在,我们知道如何使用status来更改值,我们还应该更新对POST /创建的响应方式。 虽然200响应在技术上是正确的,因为它表示“确定”,但更直观的响应代码将是201,表示“已创建”。 要进行此更改,我们将在发送前将其添加到status方法中。

res
  .status(201)
  .send({
    itemName  : newItemName
  });

更新资料

对于任何系统来说,更新通常是最困难的操作,并且此REST服务器也不例外。

SimpleDB的性质也使此操作更具挑战性。 如果是REST服务器,则更新是您要替换全部存储数据的位置; 另一方面,SimpleDB表示itemName下的各个属性/值对。

为了允许更新表示单个数据而不是名称/值对的集合,我们需要为代码目的定义一个架构(即使SimpleDB不需要一个)。 如果现在还不清楚,请不要担心,请继续阅读,我将说明要求。

与许多其他数据库系统相比,我们的模式将非常简单:仅是定义的属性数组。 对于我们的示例,我们涉及四个领域: 宠物汽车家具电话

schema      = ['pets','cars','furniture','phones'],

使用SimpleDB,您不能存储空的属性/值对,SimpleDB也不具有单个项的任何概念,因此,我们假定,如果SimpleDB不返回值,则该值不存在。 同样,如果我们尝试使用空的属性/值对更新SimpleDB项,则它将忽略该数据。 以以下数据为例:

{
  "itemName": "cil89uvnm00011ma2fykmy79c",
  "inventory": {
    "cars": [],
    "pets": [
      "cat",
      "dog"
    ]
  }
}

从逻辑上讲,我们知道cars是一个空数组,应该没有值, pets应该有两个值,但是phonesfurniture呢? 你对那些做什么? 这是我们如何翻译此更新请求以与SimpleDB一起使用的方法:

  • 将属性值为pet的属性设置为cat
  • 将具有值的属性pet放置到dog
  • 删除cars属性。
  • 删除phones属性。
  • 删除furniture属性。

如果没有至少定义属性的某种形式的架构,我们将不知道需要删除phonesfurniture 。 幸运的是,我们可以将该更新操作合并为两个SimpleDB请求,而不是五个请求:一个放置属性,一个删除属性。 现在是从发布/创建函数中提取代码的好时机,该函数可以转换值的属性/数组 对象放入属性/值对数组。

function attributeObjectToAttributeValuePairs(attrObj, replace) {
   var
     sdbAttributes   = [];

    Object.keys(attrObj).forEach(function(anAttributeName) {
      attrObj[anAttributeName].forEach(function(aValue) {
        sdbAttributes.push({
          Name    : anAttributeName,
          Value   : aValue,
          Replace : replace           //if true, then SimpleDB will overwrite rather than append more values to an attribute
        });
      });
    });

   return sdbAttributes; 
}

我们还将对create函数进行重要的更改。 我们将向所有项目添加新的属性/值。 此属性将不会添加到架构,并且实际上是只读的。

我们将添加一个名为created的属性,并将其值设置为1 。 使用SimpleDB,在添加属性和值之前检查项目是否存在的能力有限。 在每个putAttributes请求上,您都可以检查单个属性的值和是否存在-在我们的例子中,我们将使用created并检查其值为1。虽然这看起来很奇怪,但是它提供了非常重要的安全性阻止更新操作能够创建具有任意ID的新项目。

newAttributes.push({
  Name    : 'created',
  Value   : '1'
});

由于我们将执行几个异步HTTP请求,因此我们安装异步模块以简化这些回调的处理。

npm install async —-save

请记住,由于SimpleDB是分布式的,因此没有理由顺序放置属性然后删除。 我们将使用函数async.parallel运行这两个操作,并在两个操作都完成时获取回调。 AWS形式的putAttributesdeleteAttributes的响应未提供重要信息,因此如果没有错误,我们将仅发送状态码为200的空响应。

app.put(
  '/inventory/:itemID', 
  bodyParser.json(),
  function(req,res,next) {
    var
      updateValues  = {},
      deleteValues  = [];
    
    schema.forEach(function(anAttribute) {
      if ((!req.body[anAttribute]) || (req.body[anAttribute].length === 0)) {
        deleteValues.push({ Name : anAttribute});
      } else {
        updateValues[anAttribute] = req.body[anAttribute];
      }
    });
    
    async.parallel([
        function(cb) {
          //update anything that is present
          simpledb.putAttributes({
              DomainName    : sdbDomain,
              ItemName      : req.params.itemID,
              Attributes    : attributeObjectToAttributeValuePairs(updateValues,true),
              Expected      : {
                Name          : 'created',
                Value         : '1',
                Exists        : true
              }
            },
            cb
          );
        },
        function(cb) {
          //delete any attributes that not present
          simpledb.deleteAttributes({
              DomainName    : sdbDomain,
              ItemName      : req.params.itemID,
              Attributes    : deleteValues
            },
            cb
          );
        }
      ],
      function(err) {
        if (err) {
          next(err);
        } else {
          res.status(200).end();
        }
      }
    );
  }
);

为了使它动起来,让我们更新以前创建的条目。 这次,我们将使库存中只包含一个“狗”,并删除所有其他项目。 同样,使用cURL,运行命令,用您的项目ID之一替换[cuid]。

curl -H "Content-Type: application/json" -X PUT -d '{"pets" : ["dog"] }' http://localhost:3000/inventory/[cuid]

删除

如上所述,SimpleDB没有删除项目的概念,但是可以删除属性。 要删除项目,我们需要删除所有属性,并且“项目”将不再存在。

由于已经在架构中定义了属性列表,因此我们将使用deleteAttributes调用删除所有这些属性以及created属性。 按照我们的计划,此操作将与Update处于同一路径,但使用动词delete。

app.delete(
  '/inventory/:itemID', 
  function(req,res,next) {
    var
      attributesToDelete;
    
    attributesToDelete = schema.map(function(anAttribute){
      return { Name : anAttribute };
    });
    
    attributesToDelete.push({ Name : 'created' });
    
    simpledb.deleteAttributes({
        DomainName    : sdbDomain,
        ItemName      : req.params.itemID,
        Attributes    : attributesToDelete
      },
      function(err) {
        if (err) {
          next(err);
        } else {
          res.status(200).end();
        }
      }
    );
  }
);

清单

列出我们的REST动词。 为了实现列表操作,我们将使用select命令和类似SQL的查询语言。 我们的列表功能将是准系统,但它将为以后进行更复杂的检索提供良好的基础。 我们将进行一个非常简单的查询:

select * from `sdb-rest-tut` limit 100

当我们遇到get / read操作时,来自SimpleDB的响应不是很有用,因为它专注于属性/值对。 为了避免重复,我们将把get / read操作的一部分重构为一个单独的函数,并在此处使用它。 在使用它的同时,我们还将过滤掉created属性(因为它会显示在get操作中)。

function attributeValuePairsToAttributeObject(pairs) {
  var
    attributes = {};
  
  
  pairs
    .filter(function(aPair) {
      return aPair.Name !== 'created';
    })
    .forEach(function(aPair) {
    if (!attributes[aPair.Name]) { 
      attributes[aPair.Name] = [];
    }
    
    attributes[aPair.Name].push(aPair.Value);
  });
  
  return attributes;
}

通过选择操作,SimpleDB返回Items数组中的值。 每个项目都由一个对象表示,该对象包含itemName(简称Name )和属性/值对。

为了简化此响应,让我们在单个对象中返回所有内容。 首先,我们将像在读取/获取操作中一样将属性/值对转换为属性/值数组,然后我们可以添加itemName作为属性ID。

app.get(
  '/inventory',
  function(req,res,next) {
    simpledb.select({
      SelectExpression  : 'select * from `sdb-rest-tut` limit 100'
    },
    function(err,awsResp) {
      var
        items = [];
      if (err) {
        next(err);
      } else {
        items = awsResp.Items.map(function(anAwsItem) {
          var
            anItem;
          
          anItem = attributeValuePairsToAttributeObject(anAwsItem.Attributes);
          
          anItem.id = anAwsItem.Name;
          
          return anItem;
        });
        res.send(items);
      }
    });
  }
);

要查看我们的结果,我们可以使用curl:

curl -D- -X GET  http://localhost:3000/inventory

验证方式

验证本身就是一个主题,但是使用我们已经编写的代码,我们开始了一个简单的验证系统。

现在,我们只想确保用户除了架构中的内容之外什么都不能提交。 看着这对更新/认沽编写的代码后面, forEach荷兰国际集团在该模式将防止添加任何未经授权的属性,所以我们真的只需要申请类似于我们创建/后操作的东西。 在这种情况下,我们将过滤属性/值对,消除所有非架构属性。

newAttributes = newAttributes.filter(function(anAttribute) {
  return schema.indexOf(anAttribute.Name) !== -1;
});

在生产代码中,您可能需要更强大的验证系统。 我建议集成一个像ajv这样的JSON模式验证器,并构建一个位于bodyParser和route函数之间的中间件,以进行创建和更新操作。

下一步

使用本文中概述的代码,您具有存储,读取和修改数据所需的所有操作,但这只是您旅程的开始。 在大多数情况下,您需要开始考虑以下主题:

  • 认证方式
  • 分页
  • 复杂的列表/查询操作
  • 其他输出格式(xml,csv等)

由SimpleDB支持的REST服务器的基础使您可以添加中间件和其他逻辑来为应用程序构建主干。

最终的服务器代码可从GitHub上的simpledb-rest-api获得。

翻译自: https://code.tutsplus.com/tutorials/building-a-rest-api-with-aws-simpledb-and-nodejs--cms-26086

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值