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

Commit

Permalink
Add /api/v0/config endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
fbaiodias committed Feb 26, 2016
1 parent dab845f commit cf0ac05
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 16 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"scripts": {
"lint": "standard",
"coverage": "istanbul cover --print both -- _mocha tests/test-core/index.js",
"coverage:http-api": "istanbul cover --print both -- _mocha tests/test-http-api/index.js",
"test": "npm run test:node && npm run test:browser",
"test:node": "npm run test:node:core && npm run test:node:http-api && npm run test:node:cli",
"test:node:cli": "mocha tests/test-cli/index.js",
Expand Down
112 changes: 112 additions & 0 deletions src/http-api/resources/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
const ipfs = require('./../index.js').ipfs
const debug = require('debug')
const get = require('lodash.get')
const set = require('lodash.set')
const log = debug('http-api:config')
log.error = debug('http-api:config:error')

exports = module.exports

exports.getOrSet = {
// pre request handler that parses the args and returns `key` & `value` which are assigned to `request.pre.args`
parseArgs: (request, reply) => {
const parseValue = (args) => {
if (request.query.bool !== undefined) {
args.value = args.value === 'true'
} else if (request.query.json !== undefined) {
try {
args.value = JSON.parse(args.value)
} catch (err) {
log.error(err)
return reply({
Message: 'failed to unmarshal json. ' + err,
Code: 0
}).code(500).takeover()
}
}

return reply(args)
}

if (request.query.arg instanceof Array) {
return parseValue({
key: request.query.arg[0],
value: request.query.arg[1]
})
}

if (request.params.key) {
return parseValue({
key: request.params.key,
value: request.query.arg
})
}

if (!request.query.arg) {
return reply("Argument 'key' is required").code(400).takeover()
}

return reply({
key: request.query.arg
})
},

// main route handler which is called after the above `parseArgs`, but only if the args were valid
handler: (request, reply) => {
const key = request.pre.args.key
const value = request.pre.args.value

if (value === undefined) {
// Get the value of a given key
return ipfs.config.show((err, config) => {
if (err) {
log.error(err)
return reply({
Message: 'Failed to get config value: ' + err,
Code: 0
}).code(500)
}

const value = get(config, key)
if (value === undefined) {
return reply({
Message: 'Failed to get config value: key has no attributes',
Code: 0
}).code(500)
}

return reply({
Key: key,
Value: value
})
})
} else {
// Set the new value of a given key
ipfs.config.show((err, originalConfig) => {
if (err) {
log.error(err)
return reply({
Message: 'Failed to get config value: ' + err,
Code: 0
}).code(500)
}

const updatedConfig = set(originalConfig, key, value)
ipfs.config.replace(updatedConfig, (err) => {
if (err) {
log.error(err)
return reply({
Message: 'Failed to get config value: ' + err,
Code: 0
}).code(500)
}

return reply({
Key: key,
Value: value
})
})
})
}
}
}
13 changes: 8 additions & 5 deletions src/http-api/routes/config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
const api = require('./../index.js').server.select('API')
const resources = require('./../resources')

// TODO

api.route({
method: 'GET',
path: '/api/v0/config',
handler: resources.config
method: '*',
path: '/api/v0/config/{key?}',
config: {
pre: [
{ method: resources.config.getOrSet.parseArgs, assign: 'args' }
],
handler: resources.config.getOrSet.handler
}
})
2 changes: 1 addition & 1 deletion src/http-api/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ require('./bootstrap')
// require('./block')
// require('./object')
// require('./repo')
// require('./config')
require('./config')
222 changes: 212 additions & 10 deletions tests/test-http-api/test-config.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,225 @@
/* eslint-env mocha */

// const expect = require('chai').expect
// const APIctl = require('ipfs-api')
const expect = require('chai').expect
const fs = require('fs')
const APIctl = require('ipfs-api')

describe('config', () => {
const configPath = process.cwd() + '/tests/repo-tests-run/config'
const updatedConfig = () => JSON.parse(fs.readFileSync(configPath, 'utf8'))

describe('version', () => {
describe('api', () => {
// TODO
})
var api

before('api', (done) => {
api = require('../../src/http-api').server.select('API')
done()
})

describe('/config', () => {
it('returns 400 for request without arguments', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config'
}, res => {
expect(res.statusCode).to.equal(400)
done()
})
})

it('returns 500 for request with invalid argument', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config?arg=kitten'
}, res => {
expect(res.statusCode).to.equal(500)
expect(res.result.Code).to.equal(0)
expect(res.result.Message).to.be.a('string')
done()
})
})

it('returns value for request with argument', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config?arg=API.HTTPHeaders'
}, res => {
expect(res.statusCode).to.equal(200)
expect(res.result.Key).to.equal('API.HTTPHeaders')
expect(res.result.Value).to.equal(null)
done()
})
})

it('returns value for request as subcommand', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config/API.HTTPHeaders'
}, res => {
expect(res.statusCode).to.equal(200)
expect(res.result.Key).to.equal('API.HTTPHeaders')
expect(res.result.Value).to.equal(null)
done()
})
})

it('updates value for request with both args', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config?arg=Datastore.Path&arg=kitten'
}, res => {
expect(res.statusCode).to.equal(200)
expect(res.result.Key).to.equal('Datastore.Path')
expect(res.result.Value).to.equal('kitten')
expect(updatedConfig().Datastore.Path).to.equal('kitten')

done()
})
})

it('returns 500 value for request with both args and JSON flag with invalid JSON argument', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config?arg=Datastore.Path&arg=kitten&json'
}, res => {
expect(res.statusCode).to.equal(500)
expect(res.result.Code).to.equal(0)
expect(res.result.Message).to.be.a('string')

done()
})
})

it('updates value for request with both args and JSON flag with valid JSON argument', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config?arg=Datastore.Path&arg={\"kitten\": true}&json'
}, res => {
expect(res.statusCode).to.equal(200)
expect(res.result.Key).to.equal('Datastore.Path')
expect(res.result.Value).to.deep.equal({ kitten: true })
expect(updatedConfig().Datastore.Path).to.deep.equal({ kitten: true })

done()
})
})

it('updates value for request with both args and bool flag and true argument', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config?arg=Datastore.Path&arg=true&bool'
}, res => {
expect(res.statusCode).to.equal(200)
expect(res.result.Key).to.equal('Datastore.Path')
expect(res.result.Value).to.deep.equal(true)
expect(updatedConfig().Datastore.Path).to.deep.equal(true)

done()
})
})

it('updates value for request with both args and bool flag and false argument', (done) => {
api.inject({
method: 'POST',
url: '/api/v0/config?arg=Datastore.Path&arg=false&bool'
}, res => {
expect(res.statusCode).to.equal(200)
expect(res.result.Key).to.equal('Datastore.Path')
expect(res.result.Value).to.deep.equal(false)
expect(updatedConfig().Datastore.Path).to.deep.equal(false)

describe('gateway', () => {
// TODO
done()
})
})
})
})

describe('using js-ipfs-api', () => {
// var ctl
var ctl

it('start IPFS API ctl', (done) => {
// ctl = APIctl('/ip4/127.0.0.1/tcp/6001')
before('start IPFS API ctl', (done) => {
ctl = APIctl('/ip4/127.0.0.1/tcp/6001')
done()
})

describe('ipfs.config', () => {
it('returns error for request without arguments', (done) => {
ctl.config.get(null, (err, res) => {
expect(err).to.exist

done()
})
})

it('returns error for request with invalid argument', (done) => {
ctl.config.get('kittens', (err, res) => {
expect(err).to.exist

done()
})
})

it('returns value for request with argument', (done) => {
ctl.config.get('API.HTTPHeaders', (err, res) => {
expect(err).not.to.exist
expect(res.Key).to.equal('API.HTTPHeaders')
expect(res.Value).to.equal(null)

done()
})
})

it('updates value for request with both args', (done) => {
ctl.config.set('Datastore.Path', 'kitten', (err, res) => {
expect(err).not.to.exist
expect(res.Key).to.equal('Datastore.Path')
expect(res.Value).to.equal('kitten')
expect(updatedConfig().Datastore.Path).to.equal('kitten')

done()
})
})

it('returns error for request with both args and JSON flag with invalid JSON argument', (done) => {
ctl.config.set('Datastore.Path', 'kitten', { json: true }, (err, res) => {
expect(err).to.exist

done()
})
})

it('updates value for request with both args and JSON flag with valid JSON argument', (done) => {
ctl.config.set('Datastore.Path', JSON.stringify({ kitten: true }), { json: true }, (err, res) => {
expect(err).not.to.exist
expect(res.Key).to.equal('Datastore.Path')
expect(res.Value).to.deep.equal({ kitten: true })
expect(updatedConfig().Datastore.Path).to.deep.equal({ kitten: true })

done()
})
})

it('updates value for request with both args and bool flag and true argument', (done) => {
ctl.config.set('Datastore.Path', true, { bool: true }, (err, res) => {
expect(err).not.to.exist
expect(res.Key).to.equal('Datastore.Path')
expect(res.Value).to.deep.equal(true)
expect(updatedConfig().Datastore.Path).to.deep.equal(true)

done()
})
})

it('updates value for request with both args and bool flag and false argument', (done) => {
ctl.config.set('Datastore.Path', false, { bool: true }, (err, res) => {
expect(err).not.to.exist
expect(res.Key).to.equal('Datastore.Path')
expect(res.Value).to.deep.equal(false)
expect(updatedConfig().Datastore.Path).to.deep.equal(false)

done()
})
})
})
})
})

0 comments on commit cf0ac05

Please sign in to comment.