Reputation: 4028
I'm building a node wrapper for an external API and am having issues parsing the JSON response. The following code makes the request:
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
And the below code was written to test the wrapper:
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()
However, when I run the mocha test ($ mocha --compilers coffee:coffee-script
) I receive the following error:
1) Job create should create a job with address_id:
+ expected - actual
+"Michigan fan letter"
-"Error"
EDIT
Below is the response from stream
inside res.on 'data'
:
{
"id": "job_7ecc50bea15178b8e07a",
"name": "Michigan fan letter",
"price": "1.26",
"to": {
"id": "adr_43769b47aed248c2",
"name": "Harry Zhang",
"email": "[email protected]",
"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": "[email protected]",
"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"
}
Which exactly matches up to the example response in the documentation
{
"id": "job_754d8b14dd31587d6873",
"name": "Michigan fan letter",
"price": "0.96",
"to": {
"id": "adr_43769b47aed248c2",
"name": "Harry Zhang",
"email": "[email protected]",
"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": "[email protected]",
"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"
}
Here is the data from JSON.parse response
{ id: 'job_9973e060bd8147f97f5f',
name: 'Michigan fan letter',
price: '1.26',
to:
{ id: 'adr_43769b47aed248c2',
name: 'Harry Zhang',
email: '[email protected]',
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: '[email protected]',
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' }
Upvotes: 1
Views: 561
Reputation: 151441
I see three problems in that code. I don't usually use CoffeeScript. So if I'm misreading please correct me:
The callback is called like this:
cb error, response
First argument is an error object and the second argument is the response, however in the test the callback is like this:
lob.jobs.createJob data , (new_job) ->
new_job['name'].should.equal(data['name'])
So new_job
is the error object. This does not explain everything, however, because you are getting an error. But even if there were no error, the value of new_job
would not be the response.
The reason the test shows that the string Error
is the actual value is that Error
objects have a name
field which is set to the name of the class of the exception. (So new Error().name
evaluates to "Error"
.)
This section of code also looks incorrect:
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
In the if
branch the response
is set to null
and then some fields of response
are accessed. This will cause an exception. And this exception will then be interpreted as bad JSON due to the way the try... catch
clause is set. The try... catch
clause should be narrowed to cover only the JSON.parse
call:
try
response = JSON.parse response
catch e
error = new Error "Invalid JSON"
response = null
This test is incorrect:
if res.statusCode != 200 or 201
It becomes JavaScript:
if (res.statusCode !== 200 || 201)
The part after the ||
makes it always true. Something like the following CoffeeScript code seems to be what is intended:
if res.statusCode not in [200, 201]
So it does not matter if the request is successful or not. Because of the third problem, theif
test will always be true, the branch always will be taken and the second problem will always occur. So the Mocha test will always fail.
Upvotes: 2