我正在使用Yeoman,Grunt和Bower来构建一个独立于后端构建前端的平台。我的想法是我的所有(AngularJS)控制器,服务,工厂等都存在于这个项目中,然后根据grunt构建的结果注入我的服务器端代码库。
我的问题是:
如何模拟端点,以便Grunt服务器响应与我的(Rails)应用程序相同的端点?
目前我正在使用:
angular.module('myApp', ['ngResource'])
.run(['$rootScope', function ($rootScope) {
$rootScope.testState = 'test';
}]);
然后在我的每项服务中:
mockJSON = {'foo': 'myMockJSON'}
并且在每种方法上:
if($rootScope.testState == 'test'){
return mockJSON;
}
else {
real service logic with $q/$http goes here
}
然后在grunt build
之后删除testState = 'test'
。
这显然是一个相对笨拙的架构。我怎么能避免呢?我如何让Grunt响应与我的应用程序相同的端点(其中一些有动态参数)应用一些逻辑(如果需要),并提供一个json文件(可能依赖于路径参数)?
答案 0 :(得分:14)
我已经通过使用express来编写一个用静态json响应的服务器来解决这个问题。
首先,我在项目中创建了一个名为'api'的目录。在该目录中,我有以下文件:
package.json
:
{
"name": "mockAPI",
"version": "0.0.0",
"dependencies": {
"express": "~3.3.4"
}
}
然后我在此目录中运行npm install
。
index.js
:
module.exports = require('./lib/server');
lib/server.js
:
express = require('express');
var app = express();
app.get('/my/endpoint', function(req, res){
res.json({'foo': 'myMockJSON'});
});
module.exports = app
最后是我的全球Gruntfile.js
:
connect: {
options: {
port: 9000,
hostname: 'localhost',
},
livereload: {
options: {
middleware: function (connect, options) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
require('./api')
];
}
}
},
然后服务发出请求,快递服务器提供正确的JSON。
在grunt build
之后,快速服务器只需替换为rails服务器。
答案 1 :(得分:8)
从grunt-contrib-connect
v.0.7.0开始,您还可以将自定义中间件添加到现有中间件堆栈,而无需手动重建现有的中间件堆栈。
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
],
middleware: function(connect, options, middlewares) {
// inject a custom middleware into the array of default middlewares
middlewares.push(function(req, res, next) {
if (req.url !== '/my/endpoint') {
return next();
}
res.writeHead(200, {'Content-Type': 'application/json' });
res.end("{'foo': 'myMockJSON'}");
});
return middlewares;
}
}
},
有关官方文档,请参阅https://github.com/gruntjs/grunt-contrib-connect#middleware。
答案 2 :(得分:4)
或者,您可以使用grunt-connect-proxy将测试服务器中缺少的所有内容代理到实际的后端。
安装起来非常简单,只需记住一件事就是在向livereload连接中间件添加代理时最后添加它,如下所示:
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
proxySnippet
];
}
答案 3 :(得分:2)
grunt-connect-prism类似于Ruby项目VCR。它为前端开发人员提供了一种简单的方法来记录其API(或其他一些远程源)返回的HTTP响应,并在以后重放它们。它基本上是一个HTTP缓存,但适用于从事单页应用程序(SPA)的开发人员。 You can also generate stubs for API calls that don't exist, and populate them the way you want.
它有助于嘲笑复杂的&amp;开发期间的高延迟API调用。在为您的SPA编写e2e测试时,它也很有用,从等式中删除服务器。这样可以更快地执行您的e2e测试套件。
Prism的工作原理是将自定义连接中间件添加到grunt-contrib-connect插件提供的连接服务器中。在&#39;记录&#39;模式它将在文件系统上为每个响应生成一个文件,其内容如下:
{
"requestUrl": "/api/ponies",
"contentType": "application/json",
"statusCode": 200,
"data": {
"text": "my little ponies"
}
}
免责声明:我是这个项目的作者。
答案 4 :(得分:0)
您可以使用Apache代理并将REST服务器与gruntjs连接。
Apache会这样做: proxy / - &gt; gruntjs 代理/服务 - &gt; REST服务器
你会使用你的应用程序击中Apache而angular.js应用程序会认为这是在与自己交谈所以没有跨域问题。
这是一个很好的教程,介绍如何进行设置: http://alfrescoblog.com/2014/06/14/angular-js-activiti-webapp-with-activiti-rest/
答案 5 :(得分:0)
基于亚伯拉罕P的回答,这是我的替代方式。它不需要在'api'文件夹中安装express。我可以为某些文件分离模拟服务。例如,我的'api'文件夹包含3个文件:
API \
file user.js
var user = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/user') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'role' : 'admin'
})
);
}
else {
next();
}
}
module.exports = user;
file product.js
var product = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/product') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'name' : 'test',
'category': 'test'
})
);
}
else {
next();
}
}
module.exports = product;
index.js只分配所有“模块”,我们只需要。
module.exports = {
product: require('./product.js'),
user: require('./user.js')
};
我的 Gruntfile.js 文件
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app),
require('./api').user,
require('./api').product,
];
}
}
}