如何在 Node.js 中最好地创建 RESTful API [关闭]
Posted
技术标签:
【中文标题】如何在 Node.js 中最好地创建 RESTful API [关闭]【英文标题】:How to best create a RESTful API in Node.js [closed] 【发布时间】:2013-02-06 02:03:02 【问题描述】:我是 Node 的初学者(通常是所有后端 Web 开发),我已经开始在 Node.js 中编写一个 RESTful API。我正在努力解决一些问题。
我的应用程序使用 Express 和 Mongoose,我正在使用 express-resource
模块轻松地为 API 资源创建我的 CRUD 路由。但是有几件事我不满意,我认为我可以做得更好。
第一个是猫鼬。如果我想为我的 API 编写测试,我无法通过存根 Mongoose 来强制它存储在内存数据中。然而,那里的所有教程似乎都指向 Mongoose,我真的不确定我应该使用什么。
其次,我的资源似乎有很多样板代码。这真的是在 Node.js 中创建 RESTful API 的最佳方式吗?是否有其他模块可以帮助我创建我的 CRUD 路线?我相信有一些方法可以直接从架构中创建 CRUD 路由,而无需更多代码,但我真的不确定如何。
我已经看到了一些项目,例如 Tower.js 和 CompoundJS(正式名称为 RailwayJS),它们似乎是这些综合解决方案,解决的问题远不止我在这里的问题。也许我应该使用它们,但我真的只希望 Node.js 应用程序是一个 API,仅此而已。我正在独立于 API 处理前端。
为了提供一些背景信息,这是我目前的情况。目前,我在 Mongoose 中定义了一个模型:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
, Link
var LinkSchema = new Schema(
uri: String,
meta:
title: String,
desc: String
,
shares: [
uid: Schema.Types.ObjectId,
date: Date,
message: String
]
)
Link = module.exports = mongoose.model('Link')
接下来,我为 CRUD 路由定义控制器:
var mongoose = require('mongoose')
, _ = require('underscore')
, Link = mongoose.model('Link')
exports.load = function (req, id, fn)
Link.findById(req.params.link, function (err, link)
if (err)
return res.send(err)
fn(null, link)
)
exports.index = function (req, res)
var filterByUser = req.query.user ? 'shares.uid': req.query.user :
Link.find(filterByUser, function (err, links)
if (err)
return res.send(err)
res.send(links)
)
exports.create = function (req, res)
var link = new Link(req.body)
link.save(function (err)
if (err)
// TODO: send 404
return res.send(err)
res.send(link)
)
exports.show = function (req, res)
res.send(req.link)
exports.update = function (req, res)
req.link = _(req.link).extend(req.body)
req.link.save(function (err, link)
if (err)
return res.send(err)
res.send(link)
)
exports.patch = exports.update
exports.destroy = function (req, res)
req.link.remove(function (err)
if (err)
return res.send(err)
res.send()
)
最后,我使用 express-resource
模块将这些控制器映射到 Express 应用顶部的必要 CRUD 路由。
app.resource('api/links', require('../resources/links'))
【问题讨论】:
您可能有兴趣使用此工具简化流程codecanyon.net/item/… 【参考方案1】:你应该看看restify
如果你想使用express,你也可以看看我做的这个项目——叫做node-restful。
这个库似乎更成熟,但功能更多:https://github.com/jspears/mers
【讨论】:
感谢分享 node-restful 和 mers。两个看起来都不错。你为什么说我应该使用restify?它看起来和 Express 一样多,甚至更少……我不确定它有什么帮助。能解释一下就好了! 我听说过关于restify 的好消息,但看了之后似乎它实际上并没有为你生成CRUD 操作。似乎 mers 可能是最好的选择。 谢谢。我将暂时保留这个问题,看看是否有任何其他建议。 类似 mers 的库:mongo-rest 在阅读了介绍文档后,看起来 mongo-rest 和 MERS 都不允许我轻松打开/关闭某些模型的某些路由(例如 GET、POST、no PUT、DELETE),也不能它们让我可以轻松地对模型进行许可(在最简单的情况下,确保例如只有经过身份验证的用户可以 PUT/POST/DELETE)。我错过了什么吗?谢谢!【参考方案2】:Strongloop Loopback 似乎是生成 Node/MongoDB API 的另一个不错的选择。也可以生成mocha tests。
【讨论】:
+! Loopback 在 localhost 上有一个 Web 界面,可帮助您设计模型并检查生成的路由。它与数据库无关,因此您可以在其背后使用 MongoDB 或 mysql。它允许您指定ACL rules 以确保用户只能访问他们有权访问的数据。【参考方案3】:我推荐 Baucis + Express。成千上万的用户,基于 Mongoose 的模型驱动设计,非常灵活,符合规范,支持 HATEOAS/Level 3。完美满足我的所有需求。但是,我是作者 :) https://github.com/wprl/baucis
【讨论】:
【参考方案4】:看看Hapi,它是一个以配置为中心的框架,用于构建 Web 应用程序和用作 RESTful 服务的 API。
其他选项为sails.js 和actionhero
【讨论】:
对。在。这为我这个前端的家伙打开了一个全新的世界。谢谢特拉维斯!【参考方案5】:我一直在使用 Express 在 Node.js 上构建我的 RESTful API,并且通过在 Express 4 中添加路由器,构建它变得更加容易。这里有详细说明http://www.codekitchen.ca/guide-to-structuring-and-building-a-restful-api-using-express-4/
【讨论】:
【参考方案6】:尝试https://hivepod.io/ 并在完整的 MEAN 堆栈中生成您的示例。 Hivepod 构建在 BaucisJS + ExpressJS + MongoDB + AngularJS 之上。
免责声明:我致力于构建 Hivepod。
【讨论】:
【参考方案7】:Strapi 是一个新的 (2015) 框架。
他们网站上的管理界面允许您创建 API 并指定模型之间的关系。 (可以在他们的介绍视频中看到。)
但是它被设计为在 Koa 服务器上运行,而不是在 Express 上。
【讨论】:
我同意。斯特拉皮太棒了。生成快速简单的 MVC API 可以在几秒钟内完成,添加您自己的自定义业务逻辑也很简单。使用开箱即用的 crud,但可以使用插件来启用 graphql 端点。【参考方案8】:看看这个link
这个项目是使用相同的项目架构构建的,随后是 ASP.Net WebApi 2.0。这意味着它将拥有控制器、身份验证机制等。您需要做的就是创建自己的控制器。
【讨论】:
【参考方案9】:我很惊讶没有人提到Nodal。
来自网站:
Nodal 是 Node.js 的 Web 服务器,针对快速高效地构建 API 服务进行了优化。
Nodal 拥有自己的固执己见、明确、惯用和高度可扩展的框架,为您和您的团队处理所有艰难的决定。这使您可以专注于在短时间内创建有效的产品,同时最大限度地减少技术债务
它得到积极维护,在 Github 上有 3800 多颗星(在撰写本文时),内置命令行工具来生成样板代码,总体上可以快速完成工作。
【讨论】:
【参考方案10】:看看这个:
借助 Feathers,您可以在几分钟内构建原型,并在几天内构建可用于生产的实时后端和 REST API。认真的。
【讨论】:
【参考方案11】:这是当今框架的问题。
当你从谷歌搜索“最佳”、“最快”框架等等时,人们会说“嘿,你应该试试这个sails.js、feathers、Derby 等等……”
好的问题是: - 你只是为了玩这些框架 - 如果是的话,你可以轻松获得框架列表,然后开始对它们进行基准测试。
我假设大多数人是“我想做一个产品,建一个网站将来可以赚钱,或者至少它会变得流行”;好吧,你在这里搜索的关键字和注意力都是错误的,然后尝试搜索“production ready”、“enterprise ready”、“case study”这些关键字,或者去indeed.com搜索node.js,进一步找出大多数公司使用的node.js框架,答案可能只是简单地说“express”。
如果是这样,从 node.js 堆栈中,框架将几乎缩小其中的几个:Hapi、Strongloop,甚至是雅虎不流行的 Mojito
对于那些框架,至少你可以看出 - “它们真的是生产或企业准备的” - 因为它们一直在使用沃尔玛、雅虎、其他大巨头的形式,有些甚至几年了。
这可以解释为什么 Ruby on rails 和 Django 仍然主导着全栈框架市场吗?即使你看到许多“酷”的框架不断涌入市场,Meteor、Sails.js、Go 的 Revel、Java 的 Play Spark,随便你怎么称呼——这并不意味着这些框架比这两个框架差,只是意味着它们需要时间赢得市场。
当前许多框架的另一个问题是“Ror”的一种一体式克隆;从最终用户的角度来看,他们只需要一个东西来帮助他们完成工作,需要高效,需要从头到尾工作的东西,比如 Ruby on Rails,MacOS,windows,就像任何经过测试的东西本身到那时,已经被人们日常使用。
【讨论】:
【参考方案12】:这是在图书馆系统中执行 CRUD 操作的示例
var schema=require('../dbSchema');
var bookmodel=schema.model('book');
exports.getBooks = function (req,res)
bookmodel.find().exec().then((data)=>
res.send(data)
).catch((err)=>
console.log(err);
);
;
exports.getBook = function (req,res)
var bkName=req.params.Author;
bookmodel.find(Name:bkName).exec().then((data)=>
res.send(data)
).catch((err)=>
console.log(err);
);
;
exports.getAutBooks = function (req,res)
bookmodel.find(,'Author').then((data)=>
res.send(data);
).catch((err)=>
console.log(err);
);
;
exports.deleteBooks=function(req,res)
var bkName=req.params.name;
bookmodel.remove(Name:bkName).exec().then((data)=>
res.status(200);
console.log(bkName);
).catch((err)=>
console.log(err);
);
;
exports.addBooks=function(req,res)
var newBook=new bookmodel(
Name:req.body.Name,
ISBN:req.body.ISBN,
Author:req.body.Author,
Price:req.body.Price,
Year:req.body.Year,
Publisher:req.body.Publisher
);
newBook.save().then(()=>
res.status(201);
).catch((err)=>
console.log(err);
);
;
【讨论】:
【参考方案13】: var mongoose = require('../DBSchema/SchemaMapper');
var UserSchema = mongoose.model('User');
var UserController = function()
this.insert = (data) =>
return new Promise((resolve, reject) =>
var user = new UserSchema(
userName: data.userName,
password: data.password
);
user.save().then(() =>
resolve(status: 200, message: "Added new user");
).catch(err =>
reject(status: 500, message: "Error:- "+err);
)
)
this.update = (id, data) =>
return new Promise((resolve, reject) =>
UserSchema.update(_id: id, data).then(() =>
resolve(status: 200, message: "update user");
).catch(err =>
reject(status: 500, message: "Error:- " + err);
)
)
this.searchAll = () =>
return new Promise((resolve, reject) =>
UserSchema.find().exec().then((data) =>
resolve(status: 200, data: data);
).catch(err =>
reject(status: 500, message: "Error:- " + err);
)
)
this.search = (id) =>
return new Promise((resolve, reject) =>
UserSchema.find(_id:id).exec().then(user =>
resolve(status: 200, data: user);
).catch(err =>
reject(status: 500, message: "Error:- " + err);
)
)
this.delete = (id) =>
return new Promise((resolve, reject) =>
UserSchema.remove(_id:id).then(() =>
resolve(status: 200, message: "remove user");
).catch(err =>
reject(status: 500, message:"Error:- " + err);
)
)
module.exports = new UserController();
///Route
var express = require('express');
var router = express.Router();
var Controller = require('./User.Controller');
router.post('/', (req, res) =>
Controller.insert(req.body).then(data =>
res.status(data.status).send(message: data.message);
).catch(err =>
res.status(err.status).send(message: err.message);
)
);
router.put('/:id', (req, res) =>
Controller.update(req.params.id, req.body).then(data =>
res.status(data.status).send(message: data.message);
).catch(err =>
res.status(err.status).send(message: err.message);
)
);
router.get('/', (req, res) =>
Controller.searchAll().then(data =>
res.status(data.status).send(data: data.data);
).catch(err =>
res.status(err.status).send(message: err.message);
);
);
router.get('/:id', (req, res) =>
Controller.search(req.params.id).then(data =>
res.status(data.status).send(data: data.data);
).catch(err =>
res.status(err.status).send(message: err.message);
);
);
router.delete('/:id', (req, res) =>
Controller.delete(req.params.id).then(data =>
res.status(data.status).send(message: data.message);
).catch(err =>
res.status(err.status).send(message: err.message);
)
)
module.exports = router;
//db`enter code here`schema
var mongoose = require('mongoose');
const Schema = mongoose.Schema;
var Supplier =new Schema(
itemId:
type:String,
required:true
,
brand:
type:String,
required:true
,
pno:
type:String,
required:true
,
email:
type:String,
required:true
);
mongoose.model('Inventory',Inventory);
mongoose.model('Supplier',Supplier);
mongoose.connect('mongodb://127.0.0.1:27017/LAB', function (err)
if (err)
console.log(err);
process.exit(-1);
console.log("Connected to the db");
);
module.exports = mongoose;
【讨论】:
【参考方案14】:我是 express 的忠实粉丝,我一直在使用它在 Node.js 上构建更容易构建的 RESTful API。然而,当我们的应用程序开始增长时,我们最终遇到了一种情况,即 express 结构不能很好地扩展,并且随着更多的代码拆分,我们更难以维护。
我来自大量使用 SOLID 原则的 C#/Java 背景。像Java Spring / C# WebAPI
这样的框架已被证明可以创建企业级应用程序。
我想有一个框架,我可以重用我现有的 C#/Java 技能 (reuse I mean MVC architecture, OOPS, SOLID, DI, Mocks ... yeah, strong typing
)。不幸的是,我没有找到符合我要求的框架 (It should have less learning curve, minimalist codebase size, completely express compatible
)。
我说的完全兼容是什么意思?无论 express 做什么,我必须能够做到,即使我在它上面使用框架,当我查看 Strongloop Loopback 它时很好用,但它有很多文档要阅读,而且框架是耦合的,这并不是我想要的。
所以我创建了由 Typescript (has interfaces, classes, abstract classes and strong oops
) 提供支持的Dinoloop。现在这个包已经很稳定了。
使用 Dinoloop,您可以在可扩展的架构中构建企业级应用程序。
它使用依赖注入框架,但您可以配置 typescript 中可用的任何 DI 框架。 Dinoloop 使 typescript 能够用作 Nodejs REST 框架,它帮助我为 angular
和 node
项目维护通用的 typescript 代码库。
因此,Dinoloop 非常适合打字稿爱好者和 Angular 开发人员。
【讨论】:
以上是关于如何在 Node.js 中最好地创建 RESTful API [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
GraphQL 如何在 node.js 中将服务器错误与客户端错误(最好使用 TryCatch 块)分开?