Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit cf0ac05

Browse files
committedFeb 26, 2016
Add /api/v0/config endpoint
1 parent dab845f commit cf0ac05

File tree

5 files changed

+334
-16
lines changed

5 files changed

+334
-16
lines changed
 

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"scripts": {
1010
"lint": "standard",
1111
"coverage": "istanbul cover --print both -- _mocha tests/test-core/index.js",
12+
"coverage:http-api": "istanbul cover --print both -- _mocha tests/test-http-api/index.js",
1213
"test": "npm run test:node && npm run test:browser",
1314
"test:node": "npm run test:node:core && npm run test:node:http-api && npm run test:node:cli",
1415
"test:node:cli": "mocha tests/test-cli/index.js",

‎src/http-api/resources/config.js

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
const ipfs = require('./../index.js').ipfs
2+
const debug = require('debug')
3+
const get = require('lodash.get')
4+
const set = require('lodash.set')
5+
const log = debug('http-api:config')
6+
log.error = debug('http-api:config:error')
7+
8+
exports = module.exports
9+
10+
exports.getOrSet = {
11+
// pre request handler that parses the args and returns `key` & `value` which are assigned to `request.pre.args`
12+
parseArgs: (request, reply) => {
13+
const parseValue = (args) => {
14+
if (request.query.bool !== undefined) {
15+
args.value = args.value === 'true'
16+
} else if (request.query.json !== undefined) {
17+
try {
18+
args.value = JSON.parse(args.value)
19+
} catch (err) {
20+
log.error(err)
21+
return reply({
22+
Message: 'failed to unmarshal json. ' + err,
23+
Code: 0
24+
}).code(500).takeover()
25+
}
26+
}
27+
28+
return reply(args)
29+
}
30+
31+
if (request.query.arg instanceof Array) {
32+
return parseValue({
33+
key: request.query.arg[0],
34+
value: request.query.arg[1]
35+
})
36+
}
37+
38+
if (request.params.key) {
39+
return parseValue({
40+
key: request.params.key,
41+
value: request.query.arg
42+
})
43+
}
44+
45+
if (!request.query.arg) {
46+
return reply("Argument 'key' is required").code(400).takeover()
47+
}
48+
49+
return reply({
50+
key: request.query.arg
51+
})
52+
},
53+
54+
// main route handler which is called after the above `parseArgs`, but only if the args were valid
55+
handler: (request, reply) => {
56+
const key = request.pre.args.key
57+
const value = request.pre.args.value
58+
59+
if (value === undefined) {
60+
// Get the value of a given key
61+
return ipfs.config.show((err, config) => {
62+
if (err) {
63+
log.error(err)
64+
return reply({
65+
Message: 'Failed to get config value: ' + err,
66+
Code: 0
67+
}).code(500)
68+
}
69+
70+
const value = get(config, key)
71+
if (value === undefined) {
72+
return reply({
73+
Message: 'Failed to get config value: key has no attributes',
74+
Code: 0
75+
}).code(500)
76+
}
77+
78+
return reply({
79+
Key: key,
80+
Value: value
81+
})
82+
})
83+
} else {
84+
// Set the new value of a given key
85+
ipfs.config.show((err, originalConfig) => {
86+
if (err) {
87+
log.error(err)
88+
return reply({
89+
Message: 'Failed to get config value: ' + err,
90+
Code: 0
91+
}).code(500)
92+
}
93+
94+
const updatedConfig = set(originalConfig, key, value)
95+
ipfs.config.replace(updatedConfig, (err) => {
96+
if (err) {
97+
log.error(err)
98+
return reply({
99+
Message: 'Failed to get config value: ' + err,
100+
Code: 0
101+
}).code(500)
102+
}
103+
104+
return reply({
105+
Key: key,
106+
Value: value
107+
})
108+
})
109+
})
110+
}
111+
}
112+
}

‎src/http-api/routes/config.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
const api = require('./../index.js').server.select('API')
22
const resources = require('./../resources')
33

4-
// TODO
5-
64
api.route({
7-
method: 'GET',
8-
path: '/api/v0/config',
9-
handler: resources.config
5+
method: '*',
6+
path: '/api/v0/config/{key?}',
7+
config: {
8+
pre: [
9+
{ method: resources.config.getOrSet.parseArgs, assign: 'args' }
10+
],
11+
handler: resources.config.getOrSet.handler
12+
}
1013
})

‎src/http-api/routes/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ require('./bootstrap')
44
// require('./block')
55
// require('./object')
66
// require('./repo')
7-
// require('./config')
7+
require('./config')

‎tests/test-http-api/test-config.js

+212-10
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,225 @@
11
/* eslint-env mocha */
22

3-
// const expect = require('chai').expect
4-
// const APIctl = require('ipfs-api')
3+
const expect = require('chai').expect
4+
const fs = require('fs')
5+
const APIctl = require('ipfs-api')
6+
7+
describe('config', () => {
8+
const configPath = process.cwd() + '/tests/repo-tests-run/config'
9+
const updatedConfig = () => JSON.parse(fs.readFileSync(configPath, 'utf8'))
510

6-
describe('version', () => {
711
describe('api', () => {
8-
// TODO
9-
})
12+
var api
13+
14+
before('api', (done) => {
15+
api = require('../../src/http-api').server.select('API')
16+
done()
17+
})
18+
19+
describe('/config', () => {
20+
it('returns 400 for request without arguments', (done) => {
21+
api.inject({
22+
method: 'POST',
23+
url: '/api/v0/config'
24+
}, res => {
25+
expect(res.statusCode).to.equal(400)
26+
done()
27+
})
28+
})
29+
30+
it('returns 500 for request with invalid argument', (done) => {
31+
api.inject({
32+
method: 'POST',
33+
url: '/api/v0/config?arg=kitten'
34+
}, res => {
35+
expect(res.statusCode).to.equal(500)
36+
expect(res.result.Code).to.equal(0)
37+
expect(res.result.Message).to.be.a('string')
38+
done()
39+
})
40+
})
41+
42+
it('returns value for request with argument', (done) => {
43+
api.inject({
44+
method: 'POST',
45+
url: '/api/v0/config?arg=API.HTTPHeaders'
46+
}, res => {
47+
expect(res.statusCode).to.equal(200)
48+
expect(res.result.Key).to.equal('API.HTTPHeaders')
49+
expect(res.result.Value).to.equal(null)
50+
done()
51+
})
52+
})
53+
54+
it('returns value for request as subcommand', (done) => {
55+
api.inject({
56+
method: 'POST',
57+
url: '/api/v0/config/API.HTTPHeaders'
58+
}, res => {
59+
expect(res.statusCode).to.equal(200)
60+
expect(res.result.Key).to.equal('API.HTTPHeaders')
61+
expect(res.result.Value).to.equal(null)
62+
done()
63+
})
64+
})
65+
66+
it('updates value for request with both args', (done) => {
67+
api.inject({
68+
method: 'POST',
69+
url: '/api/v0/config?arg=Datastore.Path&arg=kitten'
70+
}, res => {
71+
expect(res.statusCode).to.equal(200)
72+
expect(res.result.Key).to.equal('Datastore.Path')
73+
expect(res.result.Value).to.equal('kitten')
74+
expect(updatedConfig().Datastore.Path).to.equal('kitten')
75+
76+
done()
77+
})
78+
})
79+
80+
it('returns 500 value for request with both args and JSON flag with invalid JSON argument', (done) => {
81+
api.inject({
82+
method: 'POST',
83+
url: '/api/v0/config?arg=Datastore.Path&arg=kitten&json'
84+
}, res => {
85+
expect(res.statusCode).to.equal(500)
86+
expect(res.result.Code).to.equal(0)
87+
expect(res.result.Message).to.be.a('string')
88+
89+
done()
90+
})
91+
})
92+
93+
it('updates value for request with both args and JSON flag with valid JSON argument', (done) => {
94+
api.inject({
95+
method: 'POST',
96+
url: '/api/v0/config?arg=Datastore.Path&arg={\"kitten\": true}&json'
97+
}, res => {
98+
expect(res.statusCode).to.equal(200)
99+
expect(res.result.Key).to.equal('Datastore.Path')
100+
expect(res.result.Value).to.deep.equal({ kitten: true })
101+
expect(updatedConfig().Datastore.Path).to.deep.equal({ kitten: true })
102+
103+
done()
104+
})
105+
})
106+
107+
it('updates value for request with both args and bool flag and true argument', (done) => {
108+
api.inject({
109+
method: 'POST',
110+
url: '/api/v0/config?arg=Datastore.Path&arg=true&bool'
111+
}, res => {
112+
expect(res.statusCode).to.equal(200)
113+
expect(res.result.Key).to.equal('Datastore.Path')
114+
expect(res.result.Value).to.deep.equal(true)
115+
expect(updatedConfig().Datastore.Path).to.deep.equal(true)
116+
117+
done()
118+
})
119+
})
120+
121+
it('updates value for request with both args and bool flag and false argument', (done) => {
122+
api.inject({
123+
method: 'POST',
124+
url: '/api/v0/config?arg=Datastore.Path&arg=false&bool'
125+
}, res => {
126+
expect(res.statusCode).to.equal(200)
127+
expect(res.result.Key).to.equal('Datastore.Path')
128+
expect(res.result.Value).to.deep.equal(false)
129+
expect(updatedConfig().Datastore.Path).to.deep.equal(false)
10130

11-
describe('gateway', () => {
12-
// TODO
131+
done()
132+
})
133+
})
134+
})
13135
})
14136

15137
describe('using js-ipfs-api', () => {
16-
// var ctl
138+
var ctl
17139

18-
it('start IPFS API ctl', (done) => {
19-
// ctl = APIctl('/ip4/127.0.0.1/tcp/6001')
140+
before('start IPFS API ctl', (done) => {
141+
ctl = APIctl('/ip4/127.0.0.1/tcp/6001')
20142
done()
21143
})
144+
145+
describe('ipfs.config', () => {
146+
it('returns error for request without arguments', (done) => {
147+
ctl.config.get(null, (err, res) => {
148+
expect(err).to.exist
149+
150+
done()
151+
})
152+
})
153+
154+
it('returns error for request with invalid argument', (done) => {
155+
ctl.config.get('kittens', (err, res) => {
156+
expect(err).to.exist
157+
158+
done()
159+
})
160+
})
161+
162+
it('returns value for request with argument', (done) => {
163+
ctl.config.get('API.HTTPHeaders', (err, res) => {
164+
expect(err).not.to.exist
165+
expect(res.Key).to.equal('API.HTTPHeaders')
166+
expect(res.Value).to.equal(null)
167+
168+
done()
169+
})
170+
})
171+
172+
it('updates value for request with both args', (done) => {
173+
ctl.config.set('Datastore.Path', 'kitten', (err, res) => {
174+
expect(err).not.to.exist
175+
expect(res.Key).to.equal('Datastore.Path')
176+
expect(res.Value).to.equal('kitten')
177+
expect(updatedConfig().Datastore.Path).to.equal('kitten')
178+
179+
done()
180+
})
181+
})
182+
183+
it('returns error for request with both args and JSON flag with invalid JSON argument', (done) => {
184+
ctl.config.set('Datastore.Path', 'kitten', { json: true }, (err, res) => {
185+
expect(err).to.exist
186+
187+
done()
188+
})
189+
})
190+
191+
it('updates value for request with both args and JSON flag with valid JSON argument', (done) => {
192+
ctl.config.set('Datastore.Path', JSON.stringify({ kitten: true }), { json: true }, (err, res) => {
193+
expect(err).not.to.exist
194+
expect(res.Key).to.equal('Datastore.Path')
195+
expect(res.Value).to.deep.equal({ kitten: true })
196+
expect(updatedConfig().Datastore.Path).to.deep.equal({ kitten: true })
197+
198+
done()
199+
})
200+
})
201+
202+
it('updates value for request with both args and bool flag and true argument', (done) => {
203+
ctl.config.set('Datastore.Path', true, { bool: true }, (err, res) => {
204+
expect(err).not.to.exist
205+
expect(res.Key).to.equal('Datastore.Path')
206+
expect(res.Value).to.deep.equal(true)
207+
expect(updatedConfig().Datastore.Path).to.deep.equal(true)
208+
209+
done()
210+
})
211+
})
212+
213+
it('updates value for request with both args and bool flag and false argument', (done) => {
214+
ctl.config.set('Datastore.Path', false, { bool: true }, (err, res) => {
215+
expect(err).not.to.exist
216+
expect(res.Key).to.equal('Datastore.Path')
217+
expect(res.Value).to.deep.equal(false)
218+
expect(updatedConfig().Datastore.Path).to.deep.equal(false)
219+
220+
done()
221+
})
222+
})
223+
})
22224
})
23225
})

0 commit comments

Comments
 (0)
This repository has been archived.