我正在为外部 API 构建 Node 包装器,但在解析 JSON 响应时遇到问题。以下代码发出请求:
https = require "https"
querystring = require "querystring"
API_HOST = "api.lob.com"
API_PATH = "/v1"
startResponseHandler = (req, cb) ->
if typeof cb isnt "function" then console.log "Error: callback needs to be a function!"
req.on 'response', (res) ->
response = ''
res.setEncoding 'utf8'
res.on 'data', (stream) ->
response += stream
res.on 'end', () ->
error = null
try
response = JSON.parse response
if res.statusCode != 200 or 201
response = null
error = new Error response.error.message
error.name = response.error.type
error.code = response.error.code
error.param = response.error.param
catch e
error = new Error "Invalid JSON"
response = null
cb error, response
req.on 'error', (error) ->
cb error
module.exports = lob = (api_key) ->
# This function makes the request
makeRequest = (method, path, data, cb) ->
data = querystring.stringify data
options =
hostname: API_HOST
path: "#{API_PATH}/#{path}"
method: method
auth: "#{api_key}:"
headers:
'Content-Type' : 'application/x-www-form-urlencoded'
'Content-Length' : data.length
req = https.request options
startResponseHandler req, cb
req.write data if method is "POST" or "PUT"
req.end()
# GET, POST, DELETE, PUT functions
_get = (path, cb) ->
makeRequest "GET", path, {}, cb
_post = (path, data, cb) ->
makeRequest "POST", path, data, cb
_del = (path, cb) ->
makeRequest "DELETE", path, {}, cb
_put = (path, data, cb) ->
makeRequest "PUT", path, data, cb
# Jobs
jobs:
createJob: (data, cb) ->
_post "/jobs/", data, cb
下面的代码是用来测试包装器的:
api_key = "test_0dc8d51e0acffcb1880e0f19c79b2f5b0cc"
lob = require('../src/lob')(api_key)
should = require("should")
chai = require("chai")
data =
name: "Michigan fan letter"
to: "adr_43769b47aed248c2"
from: "adr_7f9ece71fbca3796"
object1: "obj_7ca5f80b42b6dfca"
object2: "obj_12128d3aad2aa98f"
describe "Job", ->
@timeout(10000)
describe "create", ->
it "should create a job with address_id", (done) ->
lob.jobs.createJob data , (new_job) ->
new_job['name'].should.equal(data['name'])
done()
但是,当我运行 mocha 测试 ($ mocha --compilers coffee:coffee-script
) 时,我收到以下错误:
1) Job create should create a job with address_id:
+ expected - actual
+"Michigan fan letter"
-"Error"
编辑
下面是 res.on 'data'
中 stream
的响应:
{
"id": "job_7ecc50bea15178b8e07a",
"name": "Michigan fan letter",
"price": "1.26",
"to": {
"id": "adr_43769b47aed248c2",
"name": "Harry Zhang",
"email": "harry@lob.com",
"phone": "5555555555",
"address_line1": "123 Test Street",
"address_line2": "Unit 199",
"address_city": "Mountain View",
"address_state": "CA",
"address_zip": "94085",
"address_country": "UNITED STATES",
"date_created": "2013-07-20T05:53:25+00:00",
"date_modified": "2013-07-20T05:53:25+00:00",
"object": "address"
},
"from": {
"id": "adr_7f9ece71fbca3796",
"name": "Harry Zhang",
"email": "harry@lob.com",
"phone": "5555555555",
"address_line1": "123 Test Avenue",
"address_line2": "Unit 401",
"address_city": "Seattle",
"address_state": "WA",
"address_zip": "98122",
"address_country": "UNITED STATES",
"date_created": "2013-07-20T05:55:19+00:00",
"date_modified": "2013-07-20T05:55:19+00:00",
"object": "address"
},
"status": "processed",
"tracking": null,
"packaging": {
"id": "1",
"name": "Smart Packaging",
"description": "Automatically determined optimal packaging for safe and secure delivery",
"object": "packaging"
},
"service": null,
"objects": [
{
"id": "obj_7ca5f80b42b6dfca",
"name": "Michigan is great",
"quantity": "1",
"full_bleed": "0",
"double_sided": "0",
"date_created": "2013-07-20T05:57:32+00:00",
"date_modified": "2013-07-20T05:57:32+00:00",
"setting": {
"id": "101",
"type": "Documents",
"description": "Color Document",
"paper": "20lb Paper Standard",
"width": "8.500",
"length": "11.000",
"color": "Color",
"notes": "50 cents per extra page",
"object": "setting"
},
"url": "http://assets.lob.com/obj_7ca5f80b42b6dfca",
"object": "object"
},
{
"id": "obj_12128d3aad2aa98f",
"name": "GO BLUE",
"quantity": "1",
"full_bleed": "0",
"double_sided": "0",
"date_created": "2013-07-31T00:58:35+00:00",
"date_modified": "2013-07-31T00:58:35+00:00",
"setting": {
"id": "100",
"type": "Documents",
"description": "Black and White Document",
"paper": "20lb Paper Standard",
"width": "8.500",
"length": "11.000",
"color": "Black and White",
"notes": "12 cents per extra page",
"object": "setting"
},
"url": "http://assets.lob.com/obj_12128d3aad2aa98f",
"object": "object"
}
],
"date_created": "2014-01-25T03:10:10+00:00",
"date_modified": "2014-01-25T03:10:10+00:00",
"object": "job"
}
这与 documentation 中的示例响应完全匹配
{
"id": "job_754d8b14dd31587d6873",
"name": "Michigan fan letter",
"price": "0.96",
"to": {
"id": "adr_43769b47aed248c2",
"name": "Harry Zhang",
"email": "harry@lob.com",
"phone": "5555555555",
"address_line1": "123 Test Street",
"address_line2": "Unit 199",
"address_city": "Mountain View",
"address_state": "CA",
"address_zip": "94085",
"address_country": "UNITED STATES",
"date_created": "2013-07-20T05:53:25+00:00",
"date_modified": "2013-07-20T05:53:25+00:00",
"object": "address"
},
"from": {
"id": "adr_7f9ece71fbca3796",
"name": "Harry Zhang",
"email": "harry@lob.com",
"phone": "5555555555",
"address_line1": "123 Test Avenue",
"address_line2": "Unit 401",
"address_city": "Seattle",
"address_state": "WA",
"address_zip": "98122",
"address_country": "UNITED STATES",
"date_created": "2013-07-20T05:55:19+00:00",
"date_modified": "2013-07-20T05:55:19+00:00",
"object": "address"
},
"status": "processed",
"tracking": null,
"packaging": {
"id": "1",
"name": "Smart Packaging",
"description": "Automatically determined optimal packaging for safe and secure delivery",
"object": "packaging"
},
"service": null,
"objects": [
{
"id": "obj_7ca5f80b42b6dfca",
"name": "Michigan is great",
"quantity": "1",
"full_bleed": "0",
"double_sided": "0",
"date_created": "2013-07-20T05:57:32+00:00",
"date_modified": "2013-07-20T05:57:32+00:00",
"setting": {
"id": "101",
"type": "Documents",
"description": "Color Document",
"paper": "20lb Paper Standard",
"width": "8.500",
"length": "11.000",
"color": "Color",
"notes": "50 cents per extra page",
"object": "setting"
},
"object": "object"
}
],
"date_created": "2014-01-18T19:52:27+00:00",
"date_modified": "2014-01-18T19:52:27+00:00",
"object": "job"
}
这是来自 JSON.parse 响应
的数据
{ id: 'job_9973e060bd8147f97f5f',
name: 'Michigan fan letter',
price: '1.26',
to:
{ id: 'adr_43769b47aed248c2',
name: 'Harry Zhang',
email: 'harry@lob.com',
phone: '5555555555',
address_line1: '123 Test Street',
address_line2: 'Unit 199',
address_city: 'Mountain View',
address_state: 'CA',
address_zip: '94085',
address_country: 'UNITED STATES',
date_created: '2013-07-20T05:53:25+00:00',
date_modified: '2013-07-20T05:53:25+00:00',
object: 'address' },
from:
{ id: 'adr_7f9ece71fbca3796',
name: 'Harry Zhang',
email: 'harry@lob.com',
phone: '5555555555',
address_line1: '123 Test Avenue',
address_line2: 'Unit 401',
address_city: 'Seattle',
address_state: 'WA',
address_zip: '98122',
address_country: 'UNITED STATES',
date_created: '2013-07-20T05:55:19+00:00',
date_modified: '2013-07-20T05:55:19+00:00',
object: 'address' },
status: 'processed',
tracking: null,
packaging:
{ id: '1',
name: 'Smart Packaging',
description: 'Automatically determined optimal packaging for safe and secure delivery',
object: 'packaging' },
service: null,
objects:
[ { id: 'obj_7ca5f80b42b6dfca',
name: 'Michigan is great',
quantity: '1',
full_bleed: '0',
double_sided: '0',
date_created: '2013-07-20T05:57:32+00:00',
date_modified: '2013-07-20T05:57:32+00:00',
setting: [Object],
url: 'http://assets.lob.com/obj_7ca5f80b42b6dfca',
object: 'object' },
{ id: 'obj_12128d3aad2aa98f',
name: 'GO BLUE',
quantity: '1',
full_bleed: '0',
double_sided: '0',
date_created: '2013-07-31T00:58:35+00:00',
date_modified: '2013-07-31T00:58:35+00:00',
setting: [Object],
url: 'http://assets.lob.com/obj_12128d3aad2aa98f',
object: 'object' } ],
date_created: '2014-01-25T23:12:37+00:00',
date_modified: '2014-01-25T23:12:37+00:00',
object: 'job' }
最佳答案
我在该代码中发现了三个问题。我通常不使用 CoffeeScript。所以如果我误读了请纠正我:
回调是这样调用的:
cb error, response
第一个参数是一个错误对象,第二个参数是响应,但是在测试中回调是这样的:
lob.jobs.createJob data , (new_job) -> new_job['name'].should.equal(data['name'])
所以
new_job
是错误对象。但是,这并不能解释所有问题,因为您 遇到了错误。但即使没有错误,new_job
的值也不会是响应。测试显示字符串
Error
是实际值的原因是Error
对象有一个name
字段被设置为异常类的名称。 (因此new Error().name
的计算结果为"Error"
。)这段代码看起来也不正确:
try response = JSON.parse response if res.statusCode != 200 or 201 response = null error = new Error response.error.message error.name = response.error.type error.code = response.error.code error.param = response.error.param catch e error = new Error "Invalid JSON" response = null cb error, response
在
if
分支中,response
被设置为null
,然后访问response
的一些字段。这将导致异常。由于try...catch
子句的设置方式,此异常随后将被解释为错误的 JSON。try...catch
子句应该缩小到只包含JSON.parse
调用:try response = JSON.parse response catch e error = new Error "Invalid JSON" response = null
这个测试是不正确的:
if res.statusCode != 200 or 201
它变成了 JavaScript:
if (res.statusCode !== 200 || 201)
||
之后的部分使它始终为真。类似于以下 CoffeeScript 代码的东西似乎是预期的:if res.statusCode not in [200, 201]
所以请求成功与否无所谓。由于第三个问题,if
测试将始终为真,分支将始终被采用,第二个问题将始终发生。所以 Mocha 测试总是会失败。
关于javascript - 在 Node 中解析 JSON API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21273529/