2013-07-29 64 views
11

我使用Yeoman,Grunt和Bower構建一個獨立於後端的前端構建平臺。我的想法是,我所有的(AngularJS)控制器,服務,工廠等都在這個項目中,然後根據grunt構建的結果注入到我的serverside代碼庫中。使用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文件(可能取決於路徑參數)?

回答

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') 
        ]; 
       } 
      } 
     }, 

然後在服務發出請求,以及Express服務器提供正確的JSON。

grunt build之後,快遞服務器僅由一個導軌服務器替換。

+1

這工作得很好,但我怎麼能在重裝的lib/server.js變化無需重新啓動服務器? – pablomolnar

+0

這不是一個問題我最終修改了lib/server的更改並不常見(它是一個小公司)如果你想出一個 –

+2

@pablomolnar,我絕對會喜歡聽你的解決方案我寫的插件(下面的答案)允許您在dev服務器仍在運行時修改模擬響應。 http://stackoverflow.com/a/25714447/895309 –

4

或者,您可以使用grunt-connect-proxy將您的測試服務器中缺少的所有內容都代理爲實際的後端。

它的安裝非常簡單,只有一件事將代理你的livereload時要記住中間件連接添加到最後,就像這樣:

middleware: function (connect) { 
    return [ 
     lrSnippet, 
     mountFolder(connect, '.tmp'), 
     mountFolder(connect, yeomanConfig.app), 
     proxySnippet 
    ]; 
} 
8

由於grunt-contrib-connect v.0.7的。您也可以將您的自定義中間件添加到現有的中間件堆棧,而無需手動重建現有的中間件堆棧。

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

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.

它在開發過程中模擬複雜的&高延遲API調用很有用。當您僅爲您的SPA編寫e2e測試時,將該服務器從等式中移除也非常有用。這樣可以更快地執行e2e測試套件。

Prism通過向grunt-contrib-connect插件提供的連接服務器添加自定義連接中間件來工作。而在「記錄」模式下,它會生成文件系統上的每個響應文件中包含以下內容:

{ 
    "requestUrl": "/api/ponies", 
    "contentType": "application/json", 
    "statusCode": 200, 
    "data": { 
     "text": "my little ponies" 
    } 
    } 

免責聲明:我是這個項目的作者。

0

只是我的另一種方式,基於亞伯拉罕P的答案。它不需要在'api'文件夾中安裝express。我可以將某些文件的模擬服務分開。例如,我的 'API' 文件夾中包含3個文件:

API \

  • index.js //分配所有的 「模塊」,然後簡單地要求。
  • user.js的//所有嘲諷爲用戶
  • product.js //所有嘲諷產品

文件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; 

文件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.j s只是分配所有的「模塊」,我們只是要求。

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, 
      ]; 
      } 
     } 
     }