Skip to content

Commit 36dcc83

Browse files
authored
Merge pull request #18 from NYPL-discovery/noref-improvements
Improvements related to schema posting, patching
2 parents 538e5a0 + 7342e20 commit 36dcc83

7 files changed

Lines changed: 143 additions & 14 deletions

File tree

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: node_js
2+
install: npm install
3+
script: npm test

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,15 @@ To get help with any command run:
100100
nypl-data-api help [command]
101101
```
102102

103-
Note that the lib draws from the following environment variables, which you can place in `.env`:
103+
Note that the cli uses the following environment variables, read by default from `.env`:
104104

105105
- NYPL_API_BASE_URL
106106
- NYPL_OAUTH_KEY
107107
- NYPL_OAUTH_SECRET
108108
- NYPL_OAUTH_URL
109109

110+
See `.env.example` for a sample `.env` file. To specify a different `.env`, use the `--envfile` param (e.g. `--envfile config/qa.env`)
111+
110112
### Schema post
111113

112114
Run the following to upload the content of the given jsonfile to `schemas/[name]`

bin/nypl-data-api.js

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ const jsdiff = require('diff')
66
const avsc = require('avsc')
77
require('colors')
88

9-
const argv = require('minimist')(process.argv.slice(2))
9+
const argv = require('minimist')(process.argv.slice(2), {
10+
default: {
11+
envfile: '.env'
12+
}
13+
})
14+
1015
const DataApiClient = require('../')
11-
require('dotenv').config()
16+
require('dotenv').config({ path: argv.envfile })
1217

1318
const log_level = argv.log_level || 'error'
1419

@@ -28,6 +33,20 @@ var doPost = function (path, content) {
2833
})
2934
}
3035

36+
var doPatch = function (path, content) {
37+
if ((typeof content) !== 'object') {
38+
content = JSON.parse(content)
39+
}
40+
41+
client.patch(path, content)
42+
.then((resp) => {
43+
console.log(`Done PATCHing ${path}`)
44+
console.log(`Response: ${JSON.stringify(resp, null, 2)}`)
45+
}).catch((e) => {
46+
console.error('Error: ', e)
47+
})
48+
}
49+
3150
var doGet = function (path) {
3251
if (!path) throw new Error('Path required')
3352

@@ -62,25 +81,27 @@ var showDiff = function (one, two) {
6281
console.log()
6382
}
6483

65-
function promptToPost (path, content) {
66-
if (!content) throw new Error('Posting requires content to post')
84+
function promptTo (method, path, content, cb) {
85+
if (argv.content) {
86+
content = fs.readFileSync(argv.content, 'utf8')
87+
}
88+
if (!content) throw new Error(`${method}ing requires content to ${method}`)
6789

6890
try {
69-
// Assume all posted bodies are json
70-
console.log('content: ', content)
91+
// Assume all posted/patched bodies are json
7192
content = JSON.parse(content)
7293
} catch (e) {
73-
throw new Error('Content to POST does not appear to be JSON. Only JSON supported currently.')
94+
throw new Error(`Content to ${method} does not appear to be JSON. Only JSON supported currently.`)
7495
}
7596

76-
console.log('POSTING')
97+
console.log(`${method}ing`)
7798
console.log(` To endpoint: ${process.env.NYPL_API_BASE_URL}${path}:`)
7899
console.log(` Using credentials: ${process.env.NYPL_OAUTH_KEY}@${process.env.NYPL_OAUTH_URL}`)
79100
console.log(`${JSON.stringify(content, null, 2)}`)
80101
console.log('Proceed?')
81102
prompt.start()
82103
prompt.get('y/n', (e, result) => {
83-
if (result['y/n'] === 'y') doPost(path, content)
104+
if (result['y/n'] === 'y') cb(path, content)
84105
else console.log('Aborting.')
85106
})
86107
}
@@ -97,10 +118,11 @@ function schemaPost () {
97118
if (previous && next) {
98119
showDiff(previous, next)
99120
}
100-
console.log('Really upload?')
121+
const path = `schemas/${name}`
122+
console.log(`Really upload to ${process.env.NYPL_API_BASE_URL}${path} ?`)
101123
prompt.start()
102124
prompt.get('y/n', (e, result) => {
103-
if (result['y/n'] === 'y') doPost(`schemas/${name}`, next)
125+
if (result['y/n'] === 'y') doPost(path, next)
104126
else console.log('Aborting.')
105127
})
106128
}
@@ -140,7 +162,13 @@ const commandHash = {
140162
description: 'Post JSON to an arbitrary endpoint. Will prepare request and confirm before proceeding.',
141163
usage: 'nypl-data-api post [path] [inlinejson]',
142164
examples: [ 'nypl-data-api post recap/checkin-requests \'{ "foo": "bar" }\'' ],
143-
exec: (argv.y ? doPost : promptToPost)
165+
exec: (argv.y ? doPost : (path, content) => promptTo('POST', path, content, doPost))
166+
},
167+
patch: {
168+
description: 'Patch JSON to an arbitrary endpoint. Will prepare request and confirm before proceeding.',
169+
usage: 'nypl-data-api patch [path] [inlinejson]',
170+
examples: [ 'nypl-data-api patch hold-requests \'{ "success": false }\'' ],
171+
exec: (argv.y ? doPatch : (path, content) => promptTo('PATCH', path, content, doPatch))
144172
},
145173
get: {
146174
description: 'Get arbitrary endpoint.',

lib/client.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,24 @@ class Client {
8989
return this._doHttpMethod('POST', path, options)
9090
}
9191

92+
/**
93+
* PATCH a resource at an api endpoint
94+
*
95+
* @param {string} path - The path to fetch (e.g. 'current-schema/Item')
96+
* @param {Object} body - The partial object to pass with the request
97+
* @param {RequestOptions} options - A hash of options.
98+
*
99+
* @return {Promise} A promise that resolves the result data
100+
*/
101+
patch (path, body, options = {}) {
102+
options = Object.assign({
103+
body
104+
}, options)
105+
106+
log.debug(`patch("${path}", ${JSON.stringify(body)} (${typeof body}), ${JSON.stringify(options)})`)
107+
return this._doHttpMethod('PATCH', path, options)
108+
}
109+
92110
/**
93111
* DELETE an object from an api endpoint
94112
*

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"data": {
3+
"id": 1234,
4+
"jobId": "1106896193cb7216d96",
5+
"createdDate": "2021-11-16T10:17:06-05:00",
6+
"updatedDate": "2021-11-16T10:17:12-05:00",
7+
"success": false,
8+
"processed": true,
9+
"patron": "987654321",
10+
"nyplSource": "sierra-nypl",
11+
"requestType": "hold",
12+
"recordType": "i",
13+
"record": "15371503",
14+
"pickupLocation": "",
15+
"deliveryLocation": "NH",
16+
"neededBy": "2022-11-16T00:00:00-05:00",
17+
"numberOfCopies": 1,
18+
"docDeliveryData": null,
19+
"error": null
20+
},
21+
"count": 1,
22+
"statusCode": 200,
23+
"debugInfo": []
24+
}

test/patch-test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
let client = null
2+
3+
describe('Client PATCH method', function () {
4+
beforeEach(() => {
5+
client = require('./make-test-client')()
6+
})
7+
8+
afterEach(() => {
9+
client = null
10+
})
11+
12+
// This is a common patch that the
13+
// [HoldRequestResultConsumer makes](https://github.com/NYPL/hold-request-result-consumer/blob/e7bd5b04afe25cf65ed2a5ce2de0576973e592cb/src/OAuthClient/HoldRequestClient.php#L123)
14+
// makes when it detects a hold-request has been fulfilled
15+
var holdRequestPatch = {
16+
success: true,
17+
processed: true
18+
}
19+
20+
describe('when config.json=true (default)', function () {
21+
it('should accept a new schema object via PATCH and return an object', function () {
22+
return client.patch('hold-requests/1234', holdRequestPatch)
23+
.then((resp) => {
24+
expect(resp).to.be.a('object')
25+
})
26+
})
27+
28+
it('should fail if supplied body is plaintext', function () {
29+
let call = client.patch('hold-requests/1234', JSON.stringify(holdRequestPatch))
30+
return expect(call).to.be.rejected
31+
})
32+
33+
// A null/empty body should be accepted as valid if options.json===true
34+
it('should succeed if supplied body is empty', function () {
35+
let call = client.patch('hold-requests/1234')
36+
return expect(call).to.be.fulfilled
37+
})
38+
})
39+
40+
describe('when config.json=false', function () {
41+
it('should accept a plaintext body and return plain text', function () {
42+
let call = client.patch('hold-requests/1234', JSON.stringify(holdRequestPatch), { json: false })
43+
return Promise.all([
44+
expect(call).to.be.fulfilled,
45+
expect(call).to.eventually.be.a('string')
46+
])
47+
})
48+
49+
it('should fail if supplied body is not plaintext', function () {
50+
let call = client.patch('hold-requests/1234', holdRequestPatch, { json: false })
51+
return expect(call).to.be.rejected
52+
})
53+
})
54+
})

0 commit comments

Comments
 (0)