Coverage

100%
163
163
0

src/api-mock.coffee

100%
33
33
0
LineHitsSource
11fs = require 'fs'
2
31protagonist = require 'protagonist'
41express = require 'express'
51walker = require './walker'
61SslSupport = require './ssl-support'
71CorsSupport = require './cors-support'
8
91class ApiMock
101 constructor: (config) ->
1110 protagonist = config['protagonist'] if config['protagonist']
1210 express = config['express'] if config['express']
1310 @blueprintPath = config['blueprintPath'] if config['blueprintPath']
14
1510 if not @blueprintPath?
161 throw new Error "No blueprint path provided."
17
189 @configuration = config
199 @app = express()
20
219 if @configuration.options['ssl-enable']
221 sslSupport = new SslSupport(
23 @app,
24 port: @configuration.options['ssl-port'],
25 host: @configuration.options['ssl-host'],
26 cert: @configuration.options['ssl-cert'],
27 key: @configuration.options['ssl-key']
28 )
29
309 if !@configuration.options['cors-disable']
318 corsSupport = new CorsSupport @app
32
33 run: () ->
346 app = @app
35
366 try
376 data = fs.readFileSync @blueprintPath, 'utf8'
38 catch e
391 throw e
40
41 # Get JSON representation of the blueprint file
425 ast_json = ""
435 protagonist.parse data, (error, result) =>
445 if error? then throw error
454 ast_json = result.ast
46
47 # Walk AST, add routes to app
484 try
494 walker app, ast_json['resourceGroups']
50 catch error
511 throw error
52
53 # start server
543 try
553 app.listen( if @configuration?.options?.port? then @configuration.options.port else 3000 )
56 catch error
57
58
591module.exports = ApiMock
60

src/example-to-http-payload-pair.coffee

100%
28
28
0
LineHitsSource
11inheritHeaders = require './inherit-headers'
2
3# Transforms API Blueprint example to an array of Expected
4# HTTP Request and Response body and headers
51exampleToHttpPayloadPair = (example, inheritingHeaders = {}) ->
6
77 result =
8 warnings: []
9 errors: []
10 pair: {}
11
127 request = {}
137 responses = {}
14
157 if example['requests'].length > 1
161 text = "Multiple requests, using first."
171 result['warnings'].push text
18
197 if example['responses'].length == 0
201 text = "No response available. Can't create HTTP transaction."
211 result['warnings'].push text
22 else
236 selectedRequest = example['requests'][0]
24
256 if example['requests'].length == 0
261 selectedRequest =
27 body: ""
28 headers: {}
29
306 request['body'] = selectedRequest['body']
316 request['headers'] = inheritHeaders selectedRequest['headers'], inheritingHeaders
32
336 for selectedResponse in example['responses']
347 response = {}
35
367 response['body'] = selectedResponse['body']
377 response['headers'] = inheritHeaders selectedResponse['headers'], inheritingHeaders
387 response['status'] = selectedResponse['name']
397 if selectedResponse['schema'] != ""
406 response['schema'] = selectedResponse['schema']
41
427 responses[response['status']] = response
43
446 result['pair']['request'] = request
456 result['pair']['responses'] = responses
46
477 return result
48
491module.exports = exampleToHttpPayloadPair
50
51

src/expand-uri-template-with-parameters.coffee

100%
41
41
0
LineHitsSource
11ut = require 'uri-template'
2
31expandUriTemplateWithParameters = (uriTemplate, parameters) ->
413 result =
5 errors: []
6 warnings: []
7 uri: null
813 try
913 parsed = ut.parse uriTemplate
10 catch e
111 text = 'Failed to parse URI template'
121 result['errors'].push text
131 return result
14
15 # get parameters from expression object
1612 uriParameters = []
1712 for expression in parsed['expressions']
1810 for param in expression['params']
1910 uriParameters.push param['name']
20
21 # check if all parameters have an expression in URI
2212 for parameter in Object.keys(parameters)
2311 if uriParameters.indexOf(parameter) == -1
242 text = "URI template doesn\'t contain expression for parameter" + \
25 " '" + parameter + "'"
262 result['warnings'].push text
27
2812 if parsed['expressions'].length == 0
292 result['uri'] = uriTemplate
30 else
3110 ambigous = false
32
3310 for uriParameter in uriParameters
3410 if Object.keys(parameters).indexOf(uriParameter) == -1
351 ambigous = true
361 text = "Ambigous URI template. " + \
37 "Parameter not defined:" + \
38 "'" + uriParameter + "'"
391 result['warnings'].push text
40
4110 if ambigous == false
429 toExpand = {}
439 for uriParameter in uriParameters
449 param = parameters[uriParameter]
459 if param['required'] == true
465 if param['example'] == undefined
471 ambigous = true
481 text = "Ambigous URI template. " + \
49 "No example value for parameter:" + \
50 "'" + uriParameter + "'"
511 result['warnings'].push text
52 else
534 toExpand[uriParameter] = param['example']
54 else
554 if param['example'] != undefined
562 toExpand[uriParameter] = param['example']
57 else if param['default'] != undefined
581 toExpand[uriParameter] = param['default']
59
6010 if ambigous == false
618 result['uri'] = parsed.expand toExpand
62
6312 return result
64
651module.exports = expandUriTemplateWithParameters

src/inherit-headers.coffee

100%
6
6
0
LineHitsSource
11inheritHeaders = (actualHeaders, inheritingHeaders) ->
239 for name, params of inheritingHeaders
32 if actualHeaders[name] == undefined
41 actualHeaders[name] = params
5
639 return actualHeaders
7
81module.exports = inheritHeaders

src/inherit-parameters.coffee

100%
6
6
0
LineHitsSource
11inheritParameters = (actualParameters, inheritingParameters) ->
226 for name, params of inheritingParameters
32 if actualParameters[name] == undefined
41 actualParameters[name] = params
5
626 return actualParameters
7
81module.exports = inheritParameters

src/walker.coffee

100%
49
49
0
LineHitsSource
11inheritHeaders = require './inherit-headers'
21inheritParameters = require './inherit-parameters'
31expandUriTemplateWithParameters = require './expand-uri-template-with-parameters'
41exampleToHttpPayloadPair = require './example-to-http-payload-pair'
5
61ut = require 'uri-template'
71winston = require 'winston'
8
91walker = (app, resourceGroups) ->
10
115 sendResponse = (responses) ->
1225 (req, res) ->
13 # default response
143 response = responses[Object.keys(responses)[0]]
15
16 # try to find matching response based on PREFER header
173 if 'prefer' of req.headers
182 if req.headers['prefer'] of responses
191 response = responses[req.headers['prefer']]
20 else
211 winston.warn("[#{req.url}] Preferrered response #{req.headers['prefer']} not found. Falling back to #{response.status}")
22
233 for header, value of response.headers
243 headerName = value['name']
253 headerValue = value['value']
263 res.setHeader headerName, headerValue
273 res.setHeader 'Content-Length', Buffer.byteLength(response.body)
283 res.send response.status, response.body
29
305 responses = []
31
325 for group in resourceGroups
335 for resource in group['resources']
3425 for action in resource['actions']
35
36 # headers and parameters can be specified higher up in the ast and inherited
3725 action['headers'] = inheritHeaders action['headers'], resource['headers']
3825 action['parameters'] = inheritParameters action['parameters'], resource['parameters']
39
4025 if resource['uriTemplate']?
41 # removes query parameters, and converts uri template params into what express expects
42 # e.g. /templates/{templateId}/?status=good would become /templates/:templateId/
43 # TODO: replate with uri template processing
4425 path = resource['uriTemplate'].split('{?')[0].replace(new RegExp("}","g"), "").replace(new RegExp("{","g"), ":")
45
46 # the routes are generated
4725 for example in action['examples']
4825 payload = exampleToHttpPayloadPair example, action['headers']
49
5025 for warning in payload['warnings']
515 winston.warn("[#{path}] #{warning}")
52
5325 for error in payload['errors']
545 winston.error("[#{path}] #{error}")
55
5625 responses.push {
57 method: action.method
58 path: path
59 responses: payload['pair']['responses']
60 }
61
62 #sort routes
635 responses.sort (a,b) ->
6430 if (a.path > b.path)
6510 return -1
6620 if (a.path < b.path)
6710 return 1
6810 return 0
69
705 for response in responses
7125 switch response.method
72 when 'GET'
735 app.get response.path, sendResponse(response.responses)
74 when 'POST'
755 app.post response.path, sendResponse(response.responses)
76 when 'PUT'
775 app.put response.path, sendResponse(response.responses)
78 when 'DELETE'
795 app.delete response.path, sendResponse(response.responses)
80 when 'PATCH'
815 app.patch response.path, sendResponse(response.responses)
82
83
84
851module.exports = walker
86