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

Add /api/v0/config endpoint #72

Merged
merged 1 commit into from
Feb 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a comment that this is a pre request handler

// 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()
})
})
})
})
})