Skip to content
This repository has been archived by the owner on Oct 10, 2022. It is now read-only.

Commit

Permalink
Match micro-api-client response shape
Browse files Browse the repository at this point in the history
  • Loading branch information
bcomnes committed Sep 12, 2018
1 parent b13ee49 commit 029fc09
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 57 deletions.
10 changes: 2 additions & 8 deletions .vscode/launch.json
Expand Up @@ -7,15 +7,9 @@
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${file}"
},
{
"type": "node",
"request": "launch",
"name": "Run AVA test serially",
"name": "Run active AVA test",
"program": "${workspaceRoot}/node_modules/ava/profile.js",
"args": ["src/index.test.js", "--serial"]
"args": ["${file}", "--serial"]
}
]
}
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -87,14 +87,16 @@ All methods are conveniently consumed with async/await:
async function getSomeData () {
// Calls may fail!
try {
const resposnse = await client.operationId({})
const resposnse = await client.getSites()
return response
} catch (e) {
// handle error
}
}
```

If the request response includes `json` in the `contentType` header, fetch will deserialize the JSON body. Otherwise the `text` of the response is returned.

### Convenience Methods

Some methods have been added in addition to the open API methods that make certain actions simpler to perform.
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -40,6 +40,7 @@
"lodash.flatten": "^4.4.0",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"micro-api-client": "^3.3.0",
"node-fetch": "^2.2.0",
"p-map": "^1.2.0",
"p-wait-for": "^2.0.0",
Expand Down
31 changes: 10 additions & 21 deletions src/index.test.js
Expand Up @@ -4,7 +4,7 @@ const promisify = require('util.promisify')
const NetlifyAPI = require('./index')
const body = promisify(require('body'))
const fromString = require('from2-string')
const Headers = require('node-fetch').Headers
const { TextHTTPError } = require('micro-api-client')

const createServer = handler => {
const s = http.createServer(handler)
Expand All @@ -29,13 +29,13 @@ test.serial('can make basic requests', async t => {
try {
server = createServer((req, res) => {
t.is(req.url, '/v1/oauth/tickets?client_id=1234')
res.setHeader('Content-Type', 'application/json')
res.end('{"foo": "bar"}')
})

await server.listen(port)

const body = await client.createTicket()
t.is(body.status, 200)
t.deepEqual(body, { foo: 'bar' })
} catch (e) {
t.fail(e)
Expand All @@ -49,6 +49,7 @@ test.serial('can make requests with a body', async t => {
server = createServer(async (req, res) => {
t.is(req.url, '/v1/hooks?site_id=Site123')
t.is(await body(req), '{"some":"bodyParams","another":"one"}')
res.setHeader('Content-Type', 'application/json')
res.end('{"foo": "bar"}')
})

Expand All @@ -61,7 +62,6 @@ test.serial('can make requests with a body', async t => {
another: 'one'
}
})
t.is(response.status, 200)
t.deepEqual(response, { foo: 'bar' })
} catch (e) {
t.fail(e)
Expand All @@ -88,7 +88,7 @@ test.serial('path parameter assignment', async t => {
}
)
const response = await client.createHookBySiteId({ siteId: 'Site123' })
t.deepEqual(response, { body: '' }, 'Testing other path branch')
t.is(response, '', 'Testing other path branch')
} catch (e) {
t.fail(e)
}
Expand All @@ -108,22 +108,10 @@ test.serial('handles errors from API', async t => {

const error = await t.throwsAsync(client.createHookBySiteId({ siteId: 'Site123' }))
t.is(error.status, 404, 'status code is captures on error')
t.is(error.statusText, 'Test not found', 'status text is captures on error')
t.truthy(error.response, 'Error has response object')
t.truthy(error.path, 'Error has response object')
t.deepEqual(
error.opts,

{
method: 'POST',
headers: new Headers({
Authorization: 'Bearer 1234',
'User-agent': 'netlify/js-client',
accept: 'application/json'
})
},
'Opts look correct'
)
t.is(error.message, 'Test not found', 'status text is captures on error')
t.is(error.data, '', 'has an empty data field')
t.true(error instanceof TextHTTPError, 'Is instance of TextHTTPError')
t.truthy(error.stack, 'Error has stacktrace')
} catch (e) {
t.fail(e)
}
Expand Down Expand Up @@ -156,6 +144,7 @@ test.serial('binary uploads', async t => {
t.is(await body(req), 'hello world')
res.statusCode = 200
res.statusMessage = 'OK'
res.setHeader('Content-Type', 'application/json')
res.end('{"ok": true}')
})

Expand All @@ -169,7 +158,6 @@ test.serial('binary uploads', async t => {
})

t.deepEqual(response, { ok: true })
t.is(response.status, 200)
} catch (e) {
t.fail(e)
}
Expand Down Expand Up @@ -201,6 +189,7 @@ test.serial('access token can poll', async t => {
okayToResponse = true
}, 100)
server = createServer(async (req, res) => {
res.setHeader('Content-Type', 'application/json')
if (req.url == '/v1/oauth/tickets/ticket-id') {
if (!okayToResponse) {
res.end('{}')
Expand Down
41 changes: 14 additions & 27 deletions src/open-api/index.js
Expand Up @@ -4,6 +4,7 @@ const queryString = require('qs')
const fetch = require('node-fetch')
const Headers = fetch.Headers
const camelCase = require('lodash.camelcase')
const { JSONHTTPError, TextHTTPError, HTTPError, getPagination } = require('micro-api-client')

function existy(val) {
return val != null
Expand Down Expand Up @@ -78,42 +79,28 @@ exports.generateMethod = method => {
opts.headers = new Headers(Object.assign({}, this.defaultHeaders, discoveredHeaders, opts.headers))
opts.method = method.verb.toUpperCase()

// TODO: Use micro-api-client when it supports node-fetch
const response = await fetch(path, opts)
const contentType = response.headers.get('Content-Type')

if (!response.ok) {
const err = new Error(response.statusText)
err.status = response.status
err.statusText = response.statusText
err.response = response
err.path = path
err.opts = opts
const text = await response.text()
if (contentType && contentType.match(/json/)) {
try {
err.body = JSON.parse(text)
const json = await response.json()
if (!response.ok) {
throw new JSONHTTPError(response, json)
}
const pagination = getPagination(response)
return pagination ? { pagination, items: json } : json
} catch (e) {
err.body = text
throw new HTTPError(response)
}
throw err
}

const status = {
status: response.status,
statusText: response.statusText,
ok: response.ok
}

const text = await response.text()
let json
try {
json = JSON.parse(text)
} catch (e) {
json = { body: text }
if (!response.ok) {
throw new TextHTTPError(response, text)
}

// Provide access to request status info as properties, without it serializing, including arrays
// A weird idea, with nice API ergonomics
Object.setPrototypeOf(status, Object.getPrototypeOf(json))
Object.setPrototypeOf(json, status)
return json
return text
}
}

0 comments on commit 029fc09

Please sign in to comment.