8000 Merge remote-tracking branch 'core-api/master' · core-api/javascript-client@724a39d · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Mar 18, 2019. It is now read-only.

Commit 724a39d

Browse files
committed
Merge remote-tracking branch 'core-api/master'
2 parents e80aff1 + 78fe002 commit 724a39d

File tree

11 files changed

+161
-50
lines changed

11 files changed

+161
-50
lines changed

lib/client.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ function lookupLink (node, keys) {
2222
}
2323

2424
class Client {
25-
constructor (decoders = null, transports = null) {
25+
constructor (decoders = null, transports = null, csrf = null) {
2626
this.decoders = decoders || [new codecs.CoreJSONCodec(), new codecs.JSONCodec(), new codecs.TextCodec()]
27-
this.transports = transports || [new transportsModule.HTTPTransport()]
27+
this.transports = transports || [new transportsModule.HTTPTransport(csrf)]
2828
}
2929

3030
action (document, keys, params = {}) {

lib/codecs/corejson.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@ function primitiveToNode (data, baseUrl) {
5959
if (isObject && data._type === 'document') {
6060
// Document
6161
const meta = getObject(data, '_meta')
62-
const url = getString(meta, 'url')
62+
const relativeUrl = getString(meta, 'url')
63+
const url = relativeUrl ? URL(relativeUrl, baseUrl).toString() : ''
6364
const title = getString(meta, 'title')
6465
const description = getString(meta, 'description')
65-
const content = getContent(data, baseUrl)
66+
const content = getContent(data, url)
6667
return new document.Document(url, title, description, content)
6768
} else if (isObject && data._type === 'link') {
6869
// Link
@@ -82,7 +83,7 @@ function primitiveToNode (data, baseUrl) {
8283
let field = new document.Field(name, required, location, fieldDescription)
8384
fields.push(field)
8485
}
85-
return new document.Link(url, method, fields, title, description)
86+
return new document.Link(url, method, 'application/json', fields, title, description)
8687
} else if (isObject) {
8788
// Obj B41A ect
8889
let content = {}
@@ -110,7 +111,10 @@ class CoreJSONCodec {
110111
}
111112

112113
decode (text, options = {}) {
113-
const data = JSON.parse(text)
114+
let data = text
115+
if (options.preloaded === undefined || !options.preloaded) {
116+
data = JSON.parse(text)
117+
}
114118
return primitiveToNode(data, options.url)
115119
}
116120
}

lib/document.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class Document {
88
}
99

1010
class Link {
11-
constructor (url, method, fields = [], title = '', description = '') {
11+
constructor (url, method, encoding = 'application/json', fields = [], title = '', description = '') {
1212
if (url === undefined) {
1313
throw new Error('url argument is required')
1414
}
@@ -19,6 +19,7 @@ class Link {
1919

2020
this.url = url
2121
this.method = method
22+
this.encoding = encoding
2223
this.fields = fields
2324
this.title = title
2425
this.description = description

lib/errors.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,17 @@ class LinkLookupError extends Error {
1414
}
1515
}
1616

17+
class ErrorMessage extends Error {
18+
constructor (message, content) {
19+
super(message)
20+
this.message = message
21+
this.content = content
22+
this.name = 'ErrorMessage'
23+
}
24+
}
25+
1726
module.exports = {
1827
ParameterError: ParameterError,
19-
LinkLookupError: LinkLookupError
28+
LinkLookupError: LinkLookupError,
29+
ErrorMessage: ErrorMessage
2030
}

lib/transports/http.js

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ const parseResponse = (response, decoders) => {
1414
}
1515

1616
class HTTPTransport {
17-
constructor (_fetch) {
17+
constructor (csrf, _fetch) {
1818
this.schemes = ['http', 'https']
19+
this.csrf = csrf
1920
this.fetch = _fetch || fetch
2021
}
2122

2223
action (link, decoders, params = {}) {
2324
const fields = link.fields
25+
const method = link.method.toUpperCase()
2426
let queryParams = {}
2527
let pathParams = {}
2628
let formParams = {}
@@ -60,11 +62,36 @@ class HTTPTransport {
6062
}
6163
}
6264

63-
let options = {method: link.method}
65+
let options = {method: method, headers: {}}
66+
6467
if (hasBody) {
65-
options.body = JSON.stringify(formParams)
66-
options.headers = {
67-
'Content-Type': 'application/json'
68+
if (link.encoding === 'application/json') {
69+
options.body = JSON.stringify(formParams)
70+
options.headers = {
71+
'Content-Type': 'application/json'
72+
}
73+
} else if (link.encoding === 'multipart/form-data') {
74+
// FIXME!
75+
} else if (link.encoding === 'application/x-www-form-urlencoded') {
76+
var formBody = []
77+
for (var paramKey in formParams) {
78+
var encodedKey = encodeURIComponent(paramKey)
79+
var encodedValue = encodeURIComponent(formParams[paramKey])
80+
formBody.push(encodedKey + '=' + encodedValue)
81+
}
82+
formBody = formBody.join('&')
83+
84+
options.body = formBody
85+
options.headers = {
86+
'Content-Type': 'application/x-www-form-urlencoded'
87+
}
88+
}
89+
}
90+
91+
if (this.csrf) {
92+
options.credentials = 'same-origin'
93+
if (!utils.csrfSafeMethod(method)) {
94+
Object.assign(options.headers, this.csrf)
68< F438 code>95
}
6996
}
7097

@@ -76,11 +103,15 @@ class HTTPTransport {
76103

77104
return this.fetch(finalUrl, options)
78105
.then(function (response) {
79-
if (response.ok) {
80-
return parseResponse(response, decoders)
81-
} else {
82-
throw Error('Network response was not ok.')
83-
}
106+
return parseResponse(response, decoders).then(function (data) {
107+
if (response.ok) {
108+
return data
109+
} else {
110+
const title = response.status + ' ' + response.statusText
111+
const error = new errors.ErrorMessage(title, data)
112+
return Promise.reject(error)
113+
}
114+
})
84115
})
85116
}
86117
}

lib/utils.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ const negotiateDecoder = function (decoders, contentType) {
3232
throw Error(`Unsupported media in Content-Type header: ${contentType}`)
3333
}
3434

35+
const csrfSafeMethod = function (method) {
36+
// these HTTP methods do not require CSRF protection
37+
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method))
38+
}
39+
3540
module.exports = {
3641
determineTransport: determineTransport,
37-
negotiateDecoder: negotiateDecoder
42+
negotiateDecoder: negotiateDecoder,
43+
csrfSafeMethod: csrfSafeMethod
3844
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "coreapi",
3-
"version": "0.0.9",
3+
"version": "0.0.18",
44
"description": "Javascript client library for Core API",
55
"main": "lib/index.js",
66
"scripts": {

tests/__helpers__/utils.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,17 @@ const mockedFetch = function (responseBody, contentType, statusCode = 200) {
2929

3030
const echo = function (url, options = {}) {
3131
const method = options.method
32+
const headers = options.headers
3233
const body = options.body
3334

3435
return new Promise((resolve, reject) => {
3536
const textPromise = () => {
3637
return new Promise((resolve, reject) => {
3738
let result
3839
if (body) {
39-
result = `{"url": "${url}", "method": "${method}", "body": ${body}}`
40+
result = JSON.stringify({url: url, method: method, headers: headers, body: body})
4041
} else {
41-
result = `{"url": "${url}", "method": "${method}"}`
42+
result = JSON.stringify({url: url, method: method, headers: headers})
4243
}
4344
process.nextTick(
4445
resolve(result)

tests/client.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const testUtils = require('./__helpers__/utils')
66
describe('Test the Client', function () {
77
it('should get the content of page (text/html)', function () {
88
const fetch = testUtils.mockedFetch('Hello, world', 'text/html')
9-
const transport = new transportsModule.HTTPTransport(fetch)
9+
const transport = new transportsModule.HTTPTransport(null, fetch)
1010
const client = new coreapi.Client(null, [transport])
1111
const url = 'http://example.com'
1212

@@ -22,7 +22,7 @@ describe('Test the Client', function () {
2222

2323
it('should get the content of page (application/json)', function () {
2424
const fetch = testUtils.mockedFetch('{"text": "hello"}', 'application/json')
25-
const transport = new transportsModule.HTTPTransport(fetch)
25+
const transport = new transportsModule.HTTPTransport(null, fetch)
2626
const client = new coreapi.Client(null, [transport])
2727
const url = 'http://example.com'
2828

@@ -38,7 +38,7 @@ describe('Test the Client', function () {
3838

3939
it('action should get the content of page (application/json)', function () {
4040
const fetch = testUtils.mockedFetch('{"text": "hello"}', 'application/json')
41-
const transport = new transportsModule.HTTPTransport(fetch)
41+
const transport = new transportsModule.HTTPTransport(null, fetch)
4242
const client = new coreapi.Client(null, [transport])
4343
const document = new coreapi.Document('', '', '', {nested: {link: new coreapi.Link('http://example.com', 'get')}})
4444

@@ -54,7 +54,7 @@ describe('Test the Client', function () {
5454

5555
it('action should raise an error for invalid link keys', function () {
5656
const fetch = testUtils.mockedFetch('{"text": "hello"}', 'application/json')
57-
const transport = new transportsModule.HTTPTransport(fetch)
57+
const transport = new transportsModule.HTTPTransport(null, fetch)
5858
const client = new coreapi.Client(null, [transport])
5959
const document = new coreapi.Document('', '', '', {nested: {link: new coreapi.Link('http://example.com', 'get')}})
6060

tests/codecs/corejson.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('Test the CoreJSON Codec', function () {
3535
const node = codec.decode(text)
3636

3737
expect(node instanceof document.Document).toBeTruthy()
38-
expect(node.content).toEqual({link: new document.Link('http://example.com/', 'get', [new document.Field('page', false, 'query')])})
38+
expect(node.content).toEqual({link: new document.Link('http://example.com/', 'get', 'application/json', [new document.Field('page', false, 'query')])})
3939
})
4040

4141
it('should test decoding a document (including a nested link)', function () {

0 commit comments

Comments
 (0)
0