Skip to content

Commit

Permalink
Add support for put and delete requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
tobyclemson committed Mar 24, 2019
1 parent e93081e commit fa0b303
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 1 deletion.
46 changes: 46 additions & 0 deletions src/Navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,21 @@ class Navigator {
return this.postUrl(href, body, config)
}

async put (rel, body, params = {}, config = {}) {
const { href } = this.resolveLink(rel, params)
return this.putUrl(href, body, config)
}

async patch (rel, body, params = {}, config = {}) {
const { href } = this.resolveLink(rel, params)
return this.patchUrl(href, body, config)
}

async delete (rel, body, params = {}, config = {}) {
const { href } = this.resolveLink(rel, params)
return this.deleteUrl(href, body, config)
}

async getUrl (url, params, config) {
const {
status,
Expand Down Expand Up @@ -122,6 +132,26 @@ class Navigator {
return this
}

async putUrl (url, body, config) {
const {
status,
location,
body: responseBody,
response
} = await this.options.put(url, body, config)

this._status = status
this._location = location
this._response = response
this._resource = Resource.fromObject(responseBody)

if (this.options.followRedirects && status === 201) {
return this.followRedirect(config)
}

return this
}

async patchUrl (url, body, config) {
const {
status,
Expand All @@ -142,6 +172,22 @@ class Navigator {
return this
}

async deleteUrl (url, body, config) {
const {
status,
location,
body: responseBody,
response
} = await this.options.delete(url, body, config)

this._status = status
this._location = location
this._response = response
this._resource = Resource.fromObject(responseBody)

return this
}

async followRedirect (config) {
const fullLocation = makeAbsolute(
this._location, this.getHeader('location'))
Expand Down
23 changes: 22 additions & 1 deletion src/axiosOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ const axiosPost = (url, body, config) =>
response
}))

const axiosPut = (url, body, config) =>
axios.put(url, body, { ...config, validateStatus: () => true })
.then((response) => ({
status: response.status,
body: response.data,
location: response.config.url,
response
}))

const axiosPatch = (url, body, config) =>
axios.patch(url, body, { ...config, validateStatus: () => true })
.then((response) => ({
Expand All @@ -27,8 +36,20 @@ const axiosPatch = (url, body, config) =>
response
}))

const axiosDelete = (url, body, config) =>
axios.delete(url,
{ ...config, data: body, validateStatus: () => true })
.then((response) => ({
status: response.status,
body: response.data,
location: response.config.url,
response
}))

module.exports = {
get: axiosGet,
post: axiosPost,
patch: axiosPatch
put: axiosPut,
patch: axiosPatch,
delete: axiosDelete
}
75 changes: 75 additions & 0 deletions test/navigator/delete.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import faker from 'faker'
import nock from 'nock'
import { expect } from 'chai'
import Resource from '../../src/Resource'
import Navigator from '../../src/Navigator'
import * as api from '../support/api'

const baseUrl = faker.internet.url()

describe('Navigator', () => {
beforeEach(() => {
nock.cleanAll()
})

it('deletes resources in an API', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas'}
})

api.onDelete(baseUrl, '/users/thomas', {
permanent: true
})

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.delete('user', {
permanent: true
})

expect(result.status()).to.equal(204)
})

it('uses template params when creating resources', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/{id}', templated: true}
})

api.onDelete(baseUrl, '/users/thomas', {
permanent: true
})

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.delete('user', {
permanent: true
}, {
id: 'thomas'
})

expect(result.status()).to.equal(204)
})

it('adds header options for navigation', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas'}
})

const headers = {
authorization: 'some-token'
}

api.onDelete(baseUrl, '/users/thomas',
{permanent: true},
{headers})

api.onGet(baseUrl, '/users/thomas',
new Resource()
.addProperty('name', 'Thomas'))

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.delete('user', {
permanent: true
}, {}, {headers})

expect(result.status()).to.equal(204)
})
})
202 changes: 202 additions & 0 deletions test/navigator/put.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import faker from 'faker'
import nock from 'nock'
import { expect } from 'chai'
import Resource from '../../src/Resource'
import Navigator from '../../src/Navigator'
import * as api from '../support/api'

const baseUrl = faker.internet.url()

describe('Navigator', () => {
beforeEach(() => {
nock.cleanAll()
})

it('replaces resources in an API', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas'}
})

api.onPutToReplace(baseUrl, '/users/thomas', {
name: 'Thomas'
})

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.put('user', {
name: 'Thomas'
})

expect(result.status()).to.equal(200)

expect(result.resource().getProperty('name'))
.to.deep.equal('Thomas')
})

it('uses template params when creating resources', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/{id}', templated: true}
})

api.onPutToReplace(baseUrl, '/users/thomas', {
name: 'Sponge'
})

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.put('user', {
name: 'Sponge'
}, {
id: 'thomas'
})

expect(result.status()).to.equal(200)

expect(result.resource().getProperty('name'))
.to.deep.equal('Sponge')
})

it('uses absolute url when location is relative', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas'}
})

api.onPutToReplace(baseUrl, '/users/thomas', {
name: 'Thomas'
})

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.put('user', {
name: 'Thomas'
})

expect(result.status()).to.equal(200)

expect(result.resource().getProperty('name'))
.to.deep.equal('Thomas')
})

it('uses same configuration as provided on put when following redirect',
async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas'}
})

api.onPutToCreate(baseUrl, '/users/thomas', {
name: 'Thomas'
},
`${baseUrl}/users/thomas`, {
headers: { authorization: 'Bearer 1a2b3c4d' }
})

api.onGet(baseUrl, '/users/thomas',
new Resource().addProperty('name', 'Thomas'), {
headers: { authorization: 'Bearer 1a2b3c4d' }
})

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.put('user', {
name: 'Thomas'
}, {}, {
headers: {
authorization: 'Bearer 1a2b3c4d'
}
})

expect(result.status()).to.equal(200)

expect(result.resource().getProperty('name'))
.to.deep.equal('Thomas')
})

it('does not follow location headers when the status is not 201', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas', templated: true}
})

nock(baseUrl)
.put('/users/thomas', {name: 'Thomas'})
.reply(400)

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.put('user', {
name: 'Thomas'
})

expect(result.status()).to.equal(400)
})

it('does not follow location headers when the options say not to', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas'}
})

api.onPutToCreate(baseUrl, '/users/thomas', {
name: 'Thomas'
}, `${baseUrl}/users/thomas`)

const discoveryResult =
await Navigator.discover(baseUrl, {followRedirects: false})
const result = await discoveryResult.put('user', {
name: 'Thomas'
})

expect(result.status()).to.equal(201)

expect(result.getHeader('location'))
.to.deep.equal(`${baseUrl}/users/thomas`)
})

it('continues the conversation even if we do not follow redirects', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas'}
})

api.onPutToCreate(baseUrl, '/users/thomas', {
name: 'Thomas'
}, `${baseUrl}/users/thomas`)

api.onGet(baseUrl, '/users/thomas',
new Resource()
.addProperty('name', 'Thomas'))

const discoveryResult =
await Navigator.discover(baseUrl, {followRedirects: false})
const putResult = await discoveryResult.put('user', {
name: 'Thomas'
})
const result = await putResult.followRedirect()

expect(result.status()).to.equal(200)

expect(result.resource().getProperty('name'))
.to.deep.equal('Thomas')
})

it('adds header options for navigation', async () => {
api.onDiscover(baseUrl, {}, {
user: {href: '/users/thomas'}
})

const headers = {
authorization: 'some-token'
}

api.onPutToCreate(baseUrl, '/users/thomas',
{name: 'Thomas'},
`${baseUrl}/users/thomas`,
{headers})

api.onGet(baseUrl, '/users/thomas',
new Resource()
.addProperty('name', 'Thomas'))

const discoveryResult = await Navigator.discover(baseUrl)
const result = await discoveryResult.put('user', {
name: 'Thomas'
}, {}, {headers})

expect(result.status()).to.equal(200)

expect(result.resource().getProperty('name'))
.to.deep.equal('Thomas')
})
})
Loading

0 comments on commit fa0b303

Please sign in to comment.