insomnia/app/templating/extensions/response-extension.js
Gregory Schier 79b3f3fe7c Better Nunjucks Tag Editor (#234)
* Helper to tokenize Nunjucks tag

* More granular types

* Add tag definitions

* Improve editor to be more WYSIWYG

* Fixed tests

* Added raw response tag
2017-05-23 15:05:31 -07:00

166 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import jq from 'jsonpath';
import {DOMParser} from 'xmldom';
import xpath from 'xpath';
import * as models from '../../models';
import BaseExtension from './base/base-extension';
export default class ResponseExtension extends BaseExtension {
getName () {
return 'Response Value';
}
getTag () {
return 'response';
}
getDescription () {
return 'reference values from other requests';
}
getDefaultFill () {
return "response 'body', '', ''";
}
getArguments () {
return [
{
key: 'field',
label: 'Attribute',
type: 'enum',
options: [
{name: 'Body attribute of response body', value: 'body'},
{name: 'Raw Body entire response body', value: 'raw'},
{name: 'Header value of response header', value: 'header'}
]
},
{
key: 'request',
label: 'Request',
type: 'model',
model: 'Request'
},
{
key: 'filter',
type: 'string',
hide: args => args[0].value === 'raw',
label: args => {
switch (args[0].value) {
case 'body':
return 'Filter (JSONPath or XPath)';
case 'header':
return 'Header Name';
default :
return 'Filter';
}
}
}
];
}
async run (context, field, id, filter) {
if (!['body', 'header', 'raw'].includes(field)) {
throw new Error(`Invalid response field ${field}`);
}
if (field !== 'raw' && !filter) {
throw new Error(`No ${field} filter specified`);
}
const request = await models.request.getById(id);
if (!request) {
throw new Error(`Could not find request ${id}`);
}
const response = await models.response.getLatestForRequest(id);
if (!response) {
throw new Error('No responses for request');
}
if (!response.statusCode || response.statusCode < 100) {
throw new Error('No responses for request');
}
const sanitizedFilter = filter.trim();
if (field === 'header') {
return this.matchHeader(response.headers, sanitizedFilter);
} else if (field === 'raw') {
const bodyBuffer = new Buffer(response.body, response.encoding);
return bodyBuffer.toString();
} else if (field === 'body') {
const bodyBuffer = new Buffer(response.body, response.encoding);
const bodyStr = bodyBuffer.toString();
if (sanitizedFilter.indexOf('$') === 0) {
return this.matchJSONPath(bodyStr, sanitizedFilter);
} else if (sanitizedFilter.indexOf('/') === 0) {
return this.matchXPath(bodyStr, sanitizedFilter);
} else {
throw new Error(`Invalid format for response query: ${sanitizedFilter}`);
}
} else {
throw new Error(`Unknown field ${field}`);
}
}
matchJSONPath (bodyStr, query) {
let body;
let results;
try {
body = JSON.parse(bodyStr);
} catch (err) {
throw new Error(`Invalid JSON: ${err.message}`);
}
try {
results = jq.query(body, query);
} catch (err) {
throw new Error(`Invalid JSONPath query: ${query}`);
}
if (results.length === 0) {
throw new Error(`Returned no results: ${query}`);
} else if (results.length > 1) {
throw new Error(`Returned more than one result: ${query}`);
}
return results[0];
}
matchXPath (bodyStr, query) {
let results;
// This will never throw
const dom = new DOMParser().parseFromString(bodyStr);
try {
results = xpath.select(query, dom);
} catch (err) {
throw new Error(`Invalid XPath query: ${query}`);
}
if (results.length === 0) {
throw new Error(`Returned no results: ${query}`);
} else if (results.length > 1) {
throw new Error(`Returned more than one result: ${query}`);
}
return results[0].childNodes.toString();
}
matchHeader (headers, name) {
const header = headers.find(
h => h.name.toLowerCase() === name.toLowerCase()
);
if (!header) {
throw new Error(`No match for header: ${name}`);
}
return header.value;
}
}