Как лучше всего создать RESTful API в Node.js

Я новичок в Node (и вообще вся внутренняя веб-разработка), и я начал писать RESTful API в Node. Есть несколько вещей, которые я пытаюсь понять.

Мое приложение использует Express и Mongoose, и я использую express-resource модуль для легкого создания моих маршрутов CRUD для ресурсов API. Но есть пара вещей, которые меня не устраивают, и я думаю, что могу добиться большего.

Первый - мангуст. Если я хочу написать тесты для своего API, у меня нет способа заглушить Mongoose, чтобы заставить его сохранять данные в памяти. Однако все учебники указывают на Mongoose, и я действительно не уверен, что мне следует использовать.

Во-вторых, мой ресурс содержит много стандартного кода. Действительно ли это лучший способ создать RESTful API в Node.js? Существуют ли другие модули, которые помогут мне создавать маршруты 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 модуль для сопоставления этих контроллеров с необходимыми маршрутами CRUD поверх приложения Express.

app.resource('api/links', require('../resources/links'))

14 ответов

Вы должны посмотреть в restify

Если вы хотите использовать экспресс, вы также можете проверить этот проект, который я сделал - так называемый node-restful.

Эта библиотека кажется более зрелой и имеет больше возможностей: https://github.com/jspears/mers

Strongloop Loopback кажется еще одной хорошей альтернативой для генерации API Node/MongoDB. Он также может генерировать тесты мокко тоже.

Взгляните на Hapi, его ориентированную на конфигурацию инфраструктуру для создания веб-приложений и API-интерфейсов, используемых в качестве полноценного сервиса.

Другие варианты: sails.js и actionhero

Strapi - это новый (2015) каркас.

Интерфейс администратора на их веб-сайте позволяет создавать API и указывать отношения между моделями. (Как видно из вступительного ролика.)

Однако он предназначен для работы на сервере Koa, а не на Express.

Я рекомендую Baucis + Express. Тысячи пользователей, модельно-ориентированный дизайн на основе Mongoose, очень гибкий, совместимый со спецификациями, готовый к HATEOAS/Level 3. Идеально подходит для всех моих потребностей. Но тогда я автор:) https://github.com/wprl/baucis

Проверь это: введите описание изображения здесь

С помощью Feathers вы можете создавать прототипы за считанные минуты, а готовые к работе бэкэнды в реальном времени и REST API - за несколько дней. Шутки в сторону.

Вот вопросы о фреймворках в наше время.

Когда вы приходите сюда из Google в поиске "лучших", "самых быстрых" фреймворков, бла, бла, люди напишут: "Эй, тебе стоит попробовать это sails.js, перья, дерби и т. Д..."

Хорошо. Вопрос в следующем: - Вы просто для развлечения с этими фреймворками - если да, вы можете легко получить список фреймворков, а затем начать тестировать их вообще.

  • Я предполагаю, что большинство людей "я хочу создать продукт, создать сайт, который может заработать деньги в будущем, или, по крайней мере, он станет популярным";

Хорошо, все, что вы ищете по ключевым словам и внимание здесь неправильно, попробуйте поискать "ключевые слова производства", "готовые предприятия", "тематические исследования" этих ключевых слов тогда, или, возможно, перейдите на самом деле.com и искать node.js, далее выяснить, что node.js - фреймворк, используемый большинством компаний, ответ может быть просто сказать "экспресс".

если это так, из стека node.js, фреймворки будут в значительной степени сужены, некоторые из них: Hapi, Strongloop или даже не популярный Mojito от Yahoo

По крайней мере, для этих фреймворков вы можете сказать - "Они действительно готовы для производства или для предприятий", - потому что они использовали форму Walmart, от Yahoo, от других крупных гигантов с некоторого времени, некоторые даже в течение нескольких лет.

Может ли это объяснить, почему Ruby on rails и Django по-прежнему доминируют на рынках фреймворков с полным стеком? даже если вы видите, что на рынок продолжают поступать множество "крутых" фреймворков, Meteor, Sails.js, Go's Revel, Java Play Play, что бы вы ни назвали - это не означает, что эти фреймворки хуже двух, просто они требуют времени завоевать рынок.

Еще одной проблемой является то, что многие современные фреймворки являются своего рода универсальным клоном "Ror"; С точки зрения конечного пользователя, им просто нужно что-то, чтобы помочь им добиться цели, нужно продуктивно, нужно что-то, чтобы работать с начала и до конца, как Ruby on Rails, как MacOS, как Windows, как все, что было протестировано к тому времени, ежедневно использовался людьми.

Я большой поклонник экспресса и использую его для создания API-интерфейсов RESTful на Node.js, которые проще создавать. Однако, когда наше приложение начало расти, мы оказались в ситуации, когда экспресс-структура плохо масштабировалась, и с большим количеством разбитого кода нам было сложнее поддерживать.

Я из C#/Java фона, где интенсивно используются принципы SOLID. Рамки как 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).

Что я подразумеваю под полностью выраженной совместимостью? Что бы ни делал экспресс, я должен быть в состоянии сделать это, даже если я использую фреймворк поверх него, когда я посмотрел на Strongloop Loopback, его было довольно хорошо использовать, но у него было много документации, которую нужно пройти, и фреймворки были связаны Не совсем то, что я искал.

Итак, я создал Dinoloop на основе Typescript (has interfaces, classes, abstract classes and strong oops). Пакет сейчас довольно стабильный.

С Dinoloop вы можете создавать приложения уровня предприятия в масштабируемой архитектуре. Он использует платформу Dependency Injection, но вы можете настроить любые структуры DI, доступные в машинописи. Dinoloop позволяет использовать машинописный текст в качестве среды REST Nodejs, которая помогла мне поддерживать общую кодовую базу машинописи для обоих angular а также node проекты.

Таким образом, Dinoloop идеально подходит для любителей машинописи и разработчиков углов.

Посмотрите на эту ссылку

Этот проект построен с использованием той же архитектуры проекта, за которой следует ASP.Net WebApi 2.0. Это означает, что у него будут контроллеры, механизм аутентификации и т. Д. Для начала. Все, что вам нужно сделать, это создать свои собственные контроллеры.

Попробуйте https://hivepod.io/ и сгенерируйте ваш пример в полном стеке MEAN. Hivepod строится поверх BaucisJS + ExpressJS + MongoDB + AngularJS.

Отказ от ответственности: я работаю над созданием Hivepod.

Я удивлен, что никто не упомянул Nodal.

С веб-сайта:

Nodal - это веб-сервер для Node.js, оптимизированный для быстрого и эффективного создания сервисов API.

Обладая собственной самоуверенной, явной, идиоматичной и чрезвычайно расширяемой средой, Nodal позаботится о всех трудных решениях для вас и вашей команды. Это позволяет вам сосредоточиться на создании эффективного продукта за короткий промежуток времени при минимизации технического долга

Он активно поддерживается, имеет более 3800 звезд на Github (на момент написания), имеет встроенный инструмент командной строки для генерации стандартного кода и в целом быстро выполняет свою работу.

Это образец для выполнения операций 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);
    });
};

Я использовал Express для создания своих RESTful API на Node.js, и с добавлением Router в Express 4 его еще проще структурировать. Это подробно здесь http://www.codekitchen.ca/guide-to-structuring-and-building-a-restful-api-using-express-4/

    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;
Другие вопросы по тегам