Add environment to plugin (#443)

* Allow request in plugin to access current context

Signed-off-by: Xuanwo <xuanwo.cn@gmail.com>

* Add getAllHeaders API for context request

Signed-off-by: Xuanwo <xuanwo.cn@gmail.com>

* Use JSON to parse npm show's output

Signed-off-by: Xuanwo <xuanwo.cn@gmail.com>
This commit is contained in:
Xuanwo 2017-08-22 01:34:25 +08:00 committed by Gregory Schier
parent 012b1f757b
commit e805d86c32
4 changed files with 68 additions and 22 deletions

View File

@ -17,7 +17,7 @@ import * as querystring from '../common/querystring';
import * as util from '../common/misc.js'; import * as util from '../common/misc.js';
import {AUTH_AWS_IAM, AUTH_BASIC, AUTH_DIGEST, AUTH_NETRC, AUTH_NTLM, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, getAppVersion, STATUS_CODE_PLUGIN_ERROR} from '../common/constants'; import {AUTH_AWS_IAM, AUTH_BASIC, AUTH_DIGEST, AUTH_NETRC, AUTH_NTLM, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, getAppVersion, STATUS_CODE_PLUGIN_ERROR} from '../common/constants';
import {describeByteSize, hasAuthHeader, hasContentTypeHeader, hasUserAgentHeader, setDefaultProtocol} from '../common/misc'; import {describeByteSize, hasAuthHeader, hasContentTypeHeader, hasUserAgentHeader, setDefaultProtocol} from '../common/misc';
import {getRenderedRequest} from '../common/render'; import {getRenderedRequest, getRenderContext} from '../common/render';
import fs from 'fs'; import fs from 'fs';
import * as db from '../common/database'; import * as db from '../common/database';
import * as CACerts from './cacert'; import * as CACerts from './cacert';
@ -634,10 +634,11 @@ export async function send (requestId: string, environmentId: string) {
} }
const renderedRequestBeforePlugins = await getRenderedRequest(request, environmentId); const renderedRequestBeforePlugins = await getRenderedRequest(request, environmentId);
const renderedContextBeforePlugins = await getRenderContext(request, environmentId, ancestors);
let renderedRequest: RenderedRequest; let renderedRequest: RenderedRequest;
try { try {
renderedRequest = await _applyRequestPluginHooks(renderedRequestBeforePlugins); renderedRequest = await _applyRequestPluginHooks(renderedRequestBeforePlugins, renderedContextBeforePlugins);
} catch (err) { } catch (err) {
return { return {
response: { response: {
@ -661,14 +662,14 @@ export async function send (requestId: string, environmentId: string) {
return _actuallySend(renderedRequest, workspace, settings); return _actuallySend(renderedRequest, workspace, settings);
} }
async function _applyRequestPluginHooks (renderedRequest: RenderedRequest): Promise<RenderedRequest> { async function _applyRequestPluginHooks (renderedRequest: RenderedRequest, renderedContext: Object): Promise<RenderedRequest> {
let newRenderedRequest = renderedRequest; let newRenderedRequest = renderedRequest;
for (const {plugin, hook} of await plugins.getRequestHooks()) { for (const {plugin, hook} of await plugins.getRequestHooks()) {
newRenderedRequest = clone(newRenderedRequest); newRenderedRequest = clone(newRenderedRequest);
const context = { const context = {
...pluginContexts.app.init(plugin), ...pluginContexts.app.init(plugin),
...pluginContexts.request.init(plugin, newRenderedRequest) ...pluginContexts.request.init(plugin, newRenderedRequest, renderedContext)
}; };
try { try {

View File

@ -9,6 +9,14 @@ const PLUGIN = {
module: {} module: {}
}; };
const CONTEXT = {
user_key: 'my_user_key',
hello: 'world',
array_test: ['a', 'b'],
object_test: {a: 'A', b: 'B'},
null_test: null
};
describe('init()', () => { describe('init()', () => {
beforeEach(async () => { beforeEach(async () => {
await globalBeforeEach(); await globalBeforeEach();
@ -17,7 +25,7 @@ describe('init()', () => {
}); });
it('initializes correctly', async () => { it('initializes correctly', async () => {
const result = plugin.init(PLUGIN, await models.request.getById('req_1')); const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT);
expect(Object.keys(result)).toEqual(['request']); expect(Object.keys(result)).toEqual(['request']);
expect(Object.keys(result.request)).toEqual([ expect(Object.keys(result.request)).toEqual([
'getId', 'getId',
@ -25,11 +33,14 @@ describe('init()', () => {
'getUrl', 'getUrl',
'getMethod', 'getMethod',
'getHeader', 'getHeader',
'getHeaders',
'hasHeader', 'hasHeader',
'removeHeader', 'removeHeader',
'setHeader', 'setHeader',
'addHeader', 'addHeader',
'setCookie' 'setCookie',
'getEnvironmentVariable',
'getEnvironment'
]); ]);
}); });
@ -55,7 +66,7 @@ describe('request.*', () => {
}); });
it('works for basic getters', async () => { it('works for basic getters', async () => {
const result = plugin.init(PLUGIN, await models.request.getById('req_1')); const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT);
expect(result.request.getId()).toBe('req_1'); expect(result.request.getId()).toBe('req_1');
expect(result.request.getName()).toBe('My Request'); expect(result.request.getName()).toBe('My Request');
expect(result.request.getUrl()).toBe(''); expect(result.request.getUrl()).toBe('');
@ -63,7 +74,13 @@ describe('request.*', () => {
}); });
it('works for headers', async () => { it('works for headers', async () => {
const result = plugin.init(PLUGIN, await models.request.getById('req_1')); const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT);
// getHeaders()
expect(result.request.getHeaders()).toEqual([
{name: 'hello', value: 'world'},
{name: 'Content-Type', value: 'application/json'}
]);
// getHeader() // getHeader()
expect(result.request.getHeader('content-type')).toBe('application/json'); expect(result.request.getHeader('content-type')).toBe('application/json');
@ -91,10 +108,33 @@ describe('request.*', () => {
const request = await models.request.getById('req_1'); const request = await models.request.getById('req_1');
request.cookies = []; // Because the plugin technically needs a RenderedRequest request.cookies = []; // Because the plugin technically needs a RenderedRequest
const result = plugin.init(PLUGIN, request); const result = plugin.init(PLUGIN, request, CONTEXT);
result.request.setCookie('foo', 'bar'); result.request.setCookie('foo', 'bar');
result.request.setCookie('foo', 'baz'); result.request.setCookie('foo', 'baz');
expect(request.cookies).toEqual([{name: 'foo', value: 'baz'}]); expect(request.cookies).toEqual([{name: 'foo', value: 'baz'}]);
}); });
it('works for environment', async () => {
const request = await models.request.getById('req_1');
request.cookies = []; // Because the plugin technically needs a RenderedRequest
const result = plugin.init(PLUGIN, request, CONTEXT);
// getEnvironment
expect(result.request.getEnvironment()).toEqual({
user_key: 'my_user_key',
hello: 'world',
array_test: ['a', 'b'],
object_test: {a: 'A', b: 'B'},
null_test: null
});
// getEnvironmentVariable
expect(result.request.getEnvironmentVariable('user_key')).toBe('my_user_key');
expect(result.request.getEnvironmentVariable('hello')).toBe('world');
expect(result.request.getEnvironmentVariable('array_test')).toEqual(['a', 'b']);
expect(result.request.getEnvironmentVariable('object_test')).toEqual({a: 'A', b: 'B'});
expect(result.request.getEnvironmentVariable('null_test')).toBe(null);
});
}); });

View File

@ -3,7 +3,11 @@ import type {Plugin} from '../';
import type {RenderedRequest} from '../../common/render'; import type {RenderedRequest} from '../../common/render';
import * as misc from '../../common/misc'; import * as misc from '../../common/misc';
export function init (plugin: Plugin, renderedRequest: RenderedRequest): {request: Object} { export function init (
plugin: Plugin,
renderedRequest: RenderedRequest,
renderedContext: Object
): {request: Object} {
if (!renderedRequest) { if (!renderedRequest) {
throw new Error('contexts.request initialized without request'); throw new Error('contexts.request initialized without request');
} }
@ -33,6 +37,9 @@ export function init (plugin: Plugin, renderedRequest: RenderedRequest): {reques
return null; return null;
} }
}, },
getHeaders (): Array<{name: string, value: string}> {
return renderedRequest.headers.map(h => ({ name: h.name, value: h.value }));
},
hasHeader (name: string): boolean { hasHeader (name: string): boolean {
return this.getHeader(name) !== null; return this.getHeader(name) !== null;
}, },
@ -63,6 +70,12 @@ export function init (plugin: Plugin, renderedRequest: RenderedRequest): {reques
} else { } else {
renderedRequest.cookies.push({name, value}); renderedRequest.cookies.push({name, value});
} }
},
getEnvironmentVariable (name: string): string | number | boolean | Object | Array<any> | null {
return renderedContext[name];
},
getEnvironment (): string | number | boolean | Object | Array<any> | null {
return renderedContext;
} }
// NOTE: For these to make sense, we'd need to account for cookies in the jar as well // NOTE: For these to make sense, we'd need to account for cookies in the jar as well

View File

@ -71,21 +71,13 @@ export default async function (moduleName: string): Promise<void> {
async function _isInsomniaPlugin (moduleName: string): Promise<Object> { async function _isInsomniaPlugin (moduleName: string): Promise<Object> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
childProcess.exec( childProcess.exec(
`npm show ${moduleName} insomnia version name dist.shasum dist.tarball`, `npm show ${moduleName} --json`, (err, stdout, stderr) => {
(err, stdout, stderr) => {
if (err && stderr.includes('E404')) { if (err && stderr.includes('E404')) {
reject(new Error(`${moduleName} not found on npm`)); reject(new Error(`${moduleName} not found on npm`));
return; return;
} }
const lines = stdout.split('\n').filter(l => !!l); const info = JSON.parse(stdout);
const info = {};
for (const line of lines) {
const match = line.match(/(.*) = '(.*)'/);
// Strip quotes off of the value
info[match[1]] = match[2];
}
if (!info.hasOwnProperty('insomnia')) { if (!info.hasOwnProperty('insomnia')) {
reject(new Error(`"${moduleName}" not a plugin! Package missing "insomnia" attribute`)); reject(new Error(`"${moduleName}" not a plugin! Package missing "insomnia" attribute`));
@ -97,8 +89,8 @@ async function _isInsomniaPlugin (moduleName: string): Promise<Object> {
name: info.name, name: info.name,
version: info.version, version: info.version,
dist: { dist: {
shasum: info['dist.shasum'], shasum: info.dist.shasum,
tarball: info['dist.tarball'] tarball: info.dist.tarball
} }
}); });
} }