mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-28 07:04:10 +00:00
* feat: introduce HeaderList for dynamic header management in BrunoRequest and BrunoResponse - Implemented HeaderList to provide a dynamic API for managing request headers, allowing real-time reflection of changes. - Updated BrunoRequest and BrunoResponse to utilize HeaderList for header access, enhancing consistency and usability. - Added a headers proxy to maintain backward compatibility with existing header access patterns. - Introduced tests for HeaderList to ensure functionality and reliability across various header operations. * refactor: update createHeadersProxy to accept a getter function for raw headers - Modified createHeadersProxy to allow passing a function that retrieves raw headers, enhancing flexibility in header management. - Updated HeaderList to utilize the new getter function, ensuring consistent behavior when headers are modified. - Added a test to verify that bracket access reflects changes made via BrunoRequest.setHeaders. * refactor: enhance headers proxy and syncWriteMethods for improved header management - Updated createHeadersProxy to clarify precedence of PropertyList methods over header names in bracket access. - Expanded syncWriteMethods in bruno-request shim to include additional methods for better header manipulation. - Implemented a custom remove method in property-list-bridge to handle function predicates in-VM, improving the native bridge's functionality. * refactor: update header management in BrunoRequest and BrunoResponse - Renamed `req.headers` to `req.headerList` for improved clarity and consistency in header operations. - Enhanced `HeaderList` to support both dynamic and static modes for header management. - Updated shims for `req` and `res` to reflect the new header access patterns. - Modified tests to validate the new header access methods and ensure backward compatibility with raw headers. * refactor: enhance header translation methods for BrunoRequest and BrunoResponse - Added comprehensive translations for `req.headerList` and `res.headerList` methods to their respective Postman equivalents, improving consistency in header management. - Updated tests to validate the new translation methods, ensuring accurate conversion between Bruno and Postman header operations. - Enhanced existing tests to cover additional header manipulation scenarios, reinforcing the reliability of the header management system. * refactor: streamline headerList implementation in BrunoRequest and BrunoResponse - Replaced lazy initialization of `headerList` with direct instantiation in both classes for improved performance and clarity. - Removed redundant getter methods for `headerList`, simplifying the API. - Updated tests to reflect changes in headerList instantiation and ensure proper functionality. * refactor: remove header proxy * feat: add comprehensive headerList tests for request and response - Introduced multiple test files for `req.headerList` and `res.headerList` methods, covering various operations such as add, remove, clear, populate, and search methods. - Implemented tests for both dynamic and read-only scenarios, ensuring robust validation of header management functionalities. - Enhanced existing headerList methods with detailed assertions to improve reliability and maintainability of the header management system. * feat: expand STATIC_API_HINTS with additional headerList methods for req and res - Added a comprehensive list of methods for `req.headerList` and `res.headerList` to enhance autocomplete functionality. - Included various operations such as get, add, remove, and manipulation methods to improve developer experience and usability. * feat: implement support for disabled headers in headerList - Added functionality to track disabled headers in `req.headerList` and `res.headerList`, allowing for better management of header states. - Updated the `prepareRequest` and `prepareGrpcRequest` functions to include a `disabledHeaders` property. - Enhanced the `HeaderList` class to handle disabled headers, including methods to filter, count, and retrieve them. - Introduced tests to validate the behavior of disabled headers, ensuring they are correctly included in the header list while being excluded from raw headers. * feat: enhance HeaderList with case-insensitive key lookups and improved toObject method - Implemented case-insensitive key lookups for methods such as get, one, has, and indexOf in HeaderList. - Updated toObject method to support options for excluding disabled headers, handling duplicate keys, and skipping headers with falsy keys. - Modified toString method to return headers in HTTP wire format, improving consistency with standard practices. - Added comprehensive tests to validate new functionalities, ensuring robust header management and accurate behavior for both enabled and disabled headers. * feat: add context binding to iteration methods in HeaderList - Enhanced iteration methods (each, filter, find, map, reduce) in HeaderList to accept an optional context parameter, allowing for better control over the `this` binding in callback functions. - Updated the remove method to support context binding for function predicates. - Added comprehensive tests to validate the new context binding functionality across various iteration methods, ensuring robust header management. * feat: enhance HeaderList with new methods for string handling and object support - Added support for accepting an object with a key property in the `has` method, improving header existence checks. - Updated `add` and `populate` methods to accept "Key: Value" strings and multi-line header strings, enhancing flexibility in header management. - Modified `toString` method to ensure a trailing newline in the output, aligning with HTTP wire format standards. - Introduced comprehensive tests to validate new functionalities, ensuring robust header management and accurate behavior for various input types. * feat: enhance header management with support for disabled headers and context binding - Updated `mergeHeaders` function to preserve disabled headers from the request item, improving header state management. - Modified `addBrunoRequestShimToContext` and `addBrunoResponseShimToContext` to wrap eval code in blocks, preventing redeclaration conflicts. - Enhanced iteration methods in `property-list-bridge` to support context binding, allowing for better control over `this` in callbacks. - Added comprehensive tests for `req.headerList` and `res.headerList` to validate new functionalities and ensure robust header management. * feat: improve header merging to preserve disabled headers from request items - Enhanced the `mergeHeaders` function to retain disabled headers from the last entry in the request tree path, ensuring better management of header states. - Updated the logic to include disabled headers while merging, improving the overall functionality of header management. * feat: update header merging logic to consistently handle disabled headers - Refactored the `mergeHeaders` function to utilize a separate array for disabled headers, ensuring they are preserved during the merging process. - Simplified the logic for merging headers by directly combining enabled and disabled headers into the request object, enhancing clarity and maintainability. * refactor: update disabled headers handling in mergeHeaders function - Changed the implementation of disabled headers from an array to a Map for better performance and consistency. - Updated the logic in the `mergeHeaders` function to ensure disabled headers are correctly merged into the request object. - Enhanced tests to validate the handling of disabled headers, including new scenarios for folder-level and request-level overrides. * feat: enhance mergeHeaders function to support optional inclusion of disabled headers - Updated the `mergeHeaders` function to accept an options parameter, allowing for the inclusion of disabled headers in the merged result. - Modified the logic to handle disabled headers more effectively, ensuring they can be returned based on the provided options. - Adjusted calls to `mergeHeaders` in various modules to utilize the new functionality, improving header management consistency across the application. * refactor: remove disabledHeaders from prepareGrpcRequest function - Eliminated the handling of disabledHeaders in the prepareGrpcRequest function to streamline header management. - Updated the headers processing logic to focus solely on enabled headers, enhancing clarity and reducing complexity. * feat: add translations for req.headerList and res.headerList methods - Introduced new tests to translate methods from req.headerList and res.headerList to their corresponding pm.request.headers and pm.response.headers methods. - Added translations for methods: one, find, toObject, and upsert, enhancing the functionality of the header management system. * docs: update HeaderList method aliases and add clarification notes - Enhanced documentation for `prepend`, `append`, `insert`, and `insertAfter` methods to clarify that they are aliases for `add()` and include a note on the lack of support for ordering and duplicates. - Updated method comments to reflect the internal handling of headers as a plain object, ensuring better understanding of header management behavior. * fix: remove duplicate headerList initialization in BrunoRequest class - Eliminated redundant initialization of headerList in the BrunoRequest constructor, ensuring cleaner code and preventing potential issues with header management. - This change simplifies the constructor logic while maintaining the intended functionality of the headerList. * refactor: remove unimplemented headerList methods and update documentation - Removed the unimplemented methods `prepend`, `append`, `insert`, and `insertAfter` from the headerList, ensuring clarity in the API. - Updated documentation to reflect that these methods are not implemented and provide guidance to use `add()` or `upsert()` instead. - Adjusted tests to verify that calls to these methods throw appropriate not-implemented errors, enhancing the robustness of header management. * refactor: remove unused headerList append method from pre-request script - Eliminated the call to `req.headerList.append()` in the pre-request script, streamlining the header management process. - This change aligns with the recent refactor to remove unimplemented methods, ensuring clarity and consistency in the API usage. * test: update error messages for unimplemented headerList methods - Changed error messages in tests for `append`, `prepend`, `insert`, and `insertAfter` methods to indicate they are "not yet implemented" instead of "not implemented". - This update improves clarity in the test outputs, aligning with the current state of the headerList API. * refactor: remove unimplemented headerList methods and update related tests - Eliminated the unimplemented methods `prepend`, `append`, `insert`, and `insertAfter` from the HeaderList class and corresponding tests, clarifying the API usage. - Updated the documentation to guide users towards using `add()` or `upsert()` instead. - Adjusted tests to remove references to these methods, ensuring they accurately reflect the current state of the headerList API. * refactor: update HeaderList to accept raw request and response objects - Modified the HeaderList class to accept the raw request and response objects directly, simplifying the initialization process. - Updated the BrunoRequest and BrunoResponse classes to reflect this change, ensuring consistent handling of headers. - Enhanced internal methods to utilize the new structure, improving clarity and maintainability of the header management system. * refactor: enhance HeaderList header management and update tests - Updated HeaderList to track removed headers for axios interceptor, improving header casing handling. - Added new syncWriteMethods to the BrunoResponse shim for better integration. - Enhanced tests to verify the correct tracking of deleted headers and updated expectations for header management functionality. * refactor: update header translations and improve HeaderList methods - Removed unused 'idx' translations from both bruno-to-postman and postman-to-bruno translators to streamline header management. - Enhanced the HeaderList class to skip existing keys when populating headers, ensuring that current values are preserved. - Updated tests to reflect the new behavior of the populate method, verifying that existing headers are not overwritten and adjusting expectations accordingly. * refactor: update headerList.populate behavior and adjust tests - Modified the req.headerList.populate method to add new headers while preserving existing ones, ensuring that current values are not overwritten. - Updated the associated test to reflect this new behavior, verifying that existing headers remain intact and new headers are correctly added. * refactor: update HeaderList methods and translations for consistency - Renamed `each` method to `forEach` in HeaderList for consistency with standard JavaScript array methods. - Updated header management methods: replaced `add` with `append`, `upsert` with `set`, and `remove` with `delete` to better reflect their functionality. - Enhanced translations in bruno-to-postman and postman-to-bruno converters to align with the new method names. - Adjusted tests to verify the new method names and ensure correct header management behavior. * refactor: remove unused headerList methods and update related shims - Removed the `entries`, `keys`, and `values` methods from the HeaderList class to streamline the API and eliminate unused functionality. - Updated the `bruno-request` and `bruno-response` shims to reflect the removal of these methods, ensuring consistency in header management. - Adjusted tests to remove references to the deleted methods, maintaining alignment with the current state of the headerList API. * fix: ensure re-added headers are removed from __headersToDelete - Updated the HeaderList class to remove headers from the __headersToDelete array when they are re-added, preventing incorrect header deletion behavior. - Added tests to verify that re-added headers do not remain in __headersToDelete and that their values are correctly set in the raw request headers.
291 lines
7.0 KiB
JavaScript
291 lines
7.0 KiB
JavaScript
const HeaderList = require('./header-list');
|
|
|
|
class BrunoRequest {
|
|
/**
|
|
* The following properties are available as shorthand:
|
|
* - req.url
|
|
* - req.method
|
|
* - req.headers (raw headers object)
|
|
* - req.headerList (PropertyList API for headers)
|
|
* - req.timeout
|
|
* - req.body
|
|
*
|
|
* Above shorthands are useful for accessing the request properties directly in the scripts
|
|
* It must be noted that the user cannot set these properties directly.
|
|
* They should use the respective setter methods to set these properties.
|
|
*/
|
|
constructor(req) {
|
|
this.req = req;
|
|
this.url = req.url;
|
|
this.method = req.method;
|
|
this.headers = req.headers;
|
|
this.timeout = req.timeout;
|
|
this.name = req.name;
|
|
this.pathParams = req.pathParams;
|
|
this.tags = req.tags || [];
|
|
this.headerList = new HeaderList(this.req);
|
|
/**
|
|
* We automatically parse the JSON body if the content type is JSON
|
|
* This is to make it easier for the user to access the body directly
|
|
*
|
|
* It must be noted that the request data is always a string and is what gets sent over the network
|
|
* If the user wants to access the raw data, they can use getBody({raw: true}) method
|
|
*/
|
|
const isJson = this.hasJSONContentType(this.req.headers);
|
|
if (isJson) {
|
|
this.body = this.__safeParseJSON(req.data);
|
|
}
|
|
}
|
|
|
|
getUrl() {
|
|
return this.req.url;
|
|
}
|
|
|
|
setUrl(url) {
|
|
this.url = url;
|
|
this.req.url = url;
|
|
}
|
|
|
|
getHost() {
|
|
try {
|
|
const url = new URL(this.req.url);
|
|
return url.host;
|
|
} catch (e) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
getPath() {
|
|
try {
|
|
const url = new URL(this.req.url);
|
|
let pathname = url.pathname;
|
|
|
|
// If path params exist, interpolate them into the pathname
|
|
if (this.req.pathParams && Array.isArray(this.req.pathParams)) {
|
|
pathname = pathname
|
|
.split('/')
|
|
.map((segment) => {
|
|
if (segment.startsWith(':')) {
|
|
const paramName = segment.slice(1);
|
|
const pathParam = this.req.pathParams.find((param) => param.name === paramName);
|
|
if (pathParam && pathParam.value) {
|
|
return pathParam.value;
|
|
}
|
|
}
|
|
return segment;
|
|
})
|
|
.join('/');
|
|
}
|
|
|
|
return pathname;
|
|
} catch (e) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
getQueryString() {
|
|
try {
|
|
const url = new URL(this.req.url);
|
|
// Return query string without the leading '?'
|
|
return url.search ? url.search.substring(1) : '';
|
|
} catch (e) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
getMethod() {
|
|
return this.req.method;
|
|
}
|
|
|
|
getAuthMode() {
|
|
const headers = this.req.headers;
|
|
if (this.req?.oauth2) {
|
|
return 'oauth2';
|
|
} else if (this.req?.oauth1config) {
|
|
return 'oauth1';
|
|
} else if (headers?.['Authorization']?.startsWith('Bearer')) {
|
|
return 'bearer';
|
|
} else if (headers?.['Authorization']?.startsWith('Basic') || this.req?.auth?.username) {
|
|
return 'basic';
|
|
} else if (this.req?.apiKeyAuthValueForQueryParams) {
|
|
return 'apikey';
|
|
} else if (this.req?.apiKeyHeaderName && this.headers?.[this.req.apiKeyHeaderName] !== undefined) {
|
|
return 'apikey';
|
|
} else if (this.req?.awsv4) {
|
|
return 'awsv4';
|
|
} else if (this.req?.digestConfig) {
|
|
return 'digest';
|
|
} else if (headers?.['X-WSSE'] || this.req?.auth?.username) {
|
|
return 'wsse';
|
|
} else {
|
|
return 'none';
|
|
}
|
|
}
|
|
|
|
setMethod(method) {
|
|
this.method = method;
|
|
this.req.method = method;
|
|
}
|
|
|
|
getHeaders() {
|
|
return this.req.headers;
|
|
}
|
|
|
|
setHeaders(headers) {
|
|
this.req.headers = headers;
|
|
}
|
|
|
|
deleteHeaders(headers) {
|
|
headers.forEach((name) => this.deleteHeader(name));
|
|
}
|
|
|
|
getHeader(name) {
|
|
return this.req.headers[name];
|
|
}
|
|
|
|
setHeader(name, value) {
|
|
this.req.headers[name] = value;
|
|
}
|
|
|
|
deleteHeader(name) {
|
|
delete this.req.headers[name];
|
|
|
|
/**
|
|
Store header name to be applied in the axios request interceptor.
|
|
Default headers (user-agent, accept, accept-encoding, etc.) are added after
|
|
the pre-request script runs, so we track them here and delete them later.
|
|
*/
|
|
if (!this.req.__headersToDelete) {
|
|
this.req.__headersToDelete = [];
|
|
}
|
|
if (!this.req.__headersToDelete.includes(name)) {
|
|
this.req.__headersToDelete.push(name);
|
|
}
|
|
}
|
|
|
|
hasJSONContentType(headers) {
|
|
const contentType = headers?.['Content-Type'] || headers?.['content-type'] || '';
|
|
return contentType.includes('json');
|
|
}
|
|
|
|
/**
|
|
* Get the body of the request
|
|
*
|
|
* We automatically parse and return the JSON body if the content type is JSON
|
|
* If the user wants the raw body, they can pass the raw option as true
|
|
*/
|
|
getBody(options = {}) {
|
|
if (options.raw) {
|
|
return this.req.data;
|
|
}
|
|
|
|
const isJson = this.hasJSONContentType(this.req.headers);
|
|
if (isJson) {
|
|
return this.__safeParseJSON(this.req.data);
|
|
}
|
|
|
|
return this.req.data;
|
|
}
|
|
|
|
/**
|
|
* If the content type is JSON and if the data is an object
|
|
* - We set the body property as the object itself
|
|
* - We set the request data as the stringified JSON as it is what gets sent over the network
|
|
* Otherwise
|
|
* - We set the request data as the data itself
|
|
* - We set the body property as the data itself
|
|
*
|
|
* If the user wants to override this behavior, they can pass the raw option as true
|
|
*/
|
|
setBody(data, options = {}) {
|
|
if (options.raw) {
|
|
this.req.data = data;
|
|
this.body = data;
|
|
return;
|
|
}
|
|
|
|
const isJson = this.hasJSONContentType(this.req.headers);
|
|
if (isJson && this.__isObject(data)) {
|
|
this.body = data;
|
|
this.req.data = this.__safeStringifyJSON(data);
|
|
return;
|
|
}
|
|
|
|
this.req.data = data;
|
|
this.body = data;
|
|
}
|
|
|
|
setMaxRedirects(maxRedirects) {
|
|
this.req.maxRedirects = maxRedirects;
|
|
}
|
|
|
|
getTimeout() {
|
|
return this.req.timeout;
|
|
}
|
|
|
|
setTimeout(timeout) {
|
|
this.timeout = timeout;
|
|
this.req.timeout = timeout;
|
|
}
|
|
|
|
onFail(callback) {
|
|
if (typeof callback === 'function') {
|
|
this.req.onFailHandler = callback;
|
|
} else if (callback) {
|
|
throw new Error(`${callback} is not a function`);
|
|
}
|
|
}
|
|
|
|
__safeParseJSON(str) {
|
|
try {
|
|
return JSON.parse(str);
|
|
} catch (e) {
|
|
return str;
|
|
}
|
|
}
|
|
|
|
__safeStringifyJSON(obj) {
|
|
try {
|
|
return JSON.stringify(obj);
|
|
} catch (e) {
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
__isObject(obj) {
|
|
return obj !== null && typeof obj === 'object';
|
|
}
|
|
|
|
disableParsingResponseJson() {
|
|
this.req.__brunoDisableParsingResponseJson = true;
|
|
}
|
|
|
|
getExecutionMode() {
|
|
return this.req.__bruno__executionMode;
|
|
}
|
|
|
|
getName() {
|
|
return this.req.name;
|
|
}
|
|
|
|
getPathParams() {
|
|
const params = Array.isArray(this.req.pathParams) ? this.req.pathParams : [];
|
|
|
|
return params.map((param) => ({
|
|
name: param.name,
|
|
value: param.value,
|
|
type: param.type
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Get the tags associated with this request
|
|
* @returns {Array<string>} Array of tag strings
|
|
*/
|
|
getTags() {
|
|
return this.req.tags || [];
|
|
}
|
|
}
|
|
|
|
module.exports = BrunoRequest;
|