javascript - 在 Node 中解析 JSON API

标签 javascript json node.js coffeescript mocha.js

我正在为外部 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。所以如果我误读了请纠正我:

  1. 回调是这样调用的:

    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"。)

  2. 这段代码看起来也不正确:

    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
    
  3. 这个测试是不正确的:

      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/

相关文章:

java - 如何将 java bean 转换为 json?

javascript - 使用 twilio Passthrough API 向多个号码发送消息

javascript - 处理多个请求,而前一个请求不会阻塞下一个请求

node.js - 触发 GET 请求并获取 Node Stream

javascript - 在 jquery 中向数字(如 123,456.78)添加逗号的最佳方法

javascript - 递归地从html中删除空节点

javascript - Dojo 的依赖问题 -Uncaught TypeError : chart. addPlot 不是函数

json - 编码/解码后的结构变化

json - 从后台线程修改自动布局引擎

javascript - Angular js - 格式化日期时间以匹配条件