mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-27 22:54:07 +00:00
feat: yaml lang - parseRequest and stringifyRequest
This commit is contained in:
346
packages/bruno-lang/v3/src/common.js
Normal file
346
packages/bruno-lang/v3/src/common.js
Normal file
@@ -0,0 +1,346 @@
|
||||
const _ = require('lodash');
|
||||
|
||||
const getMeta = (json) => {
|
||||
const sequence = _.get(json, 'seq');
|
||||
const meta = {
|
||||
name: _.get(json, 'name')
|
||||
};
|
||||
|
||||
const description = _.get(json, 'description');
|
||||
if (description) {
|
||||
meta.description = description;
|
||||
}
|
||||
|
||||
meta.seq = !isNaN(sequence) ? Number(sequence) : 1;
|
||||
|
||||
return meta;
|
||||
};
|
||||
|
||||
const getParams = (req) => {
|
||||
return {
|
||||
query: _.map(_.filter(req?.params || [], param => param.type === 'query'), (param) => {
|
||||
const paramObj = {
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
type: param.type
|
||||
};
|
||||
|
||||
if (param.description) {
|
||||
paramObj.description = param.description;
|
||||
}
|
||||
|
||||
if (param.enabled === false) {
|
||||
paramObj.disabled = true;
|
||||
}
|
||||
|
||||
return paramObj;
|
||||
}),
|
||||
path: _.map(_.filter(req?.params || [], param => param.type === 'path'), (param) => {
|
||||
const paramObj = {
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
type: param.type
|
||||
};
|
||||
|
||||
if (param.description) {
|
||||
paramObj.description = param.description;
|
||||
}
|
||||
|
||||
if (param.enabled === false) {
|
||||
paramObj.disabled = true;
|
||||
}
|
||||
|
||||
return paramObj;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const getHeaders = (req) => {
|
||||
return _.map(_.get(req, 'headers', []), (header) => {
|
||||
const headerObj = {
|
||||
name: header.name,
|
||||
value: header.value,
|
||||
};
|
||||
|
||||
if (header.description) {
|
||||
headerObj.description = header.description;
|
||||
}
|
||||
|
||||
if (header.enabled === false) {
|
||||
headerObj.disabled = true;
|
||||
}
|
||||
|
||||
return headerObj;
|
||||
});
|
||||
};
|
||||
|
||||
const getBody = (req) => {
|
||||
const body = _.get(req, 'body', {});
|
||||
const mode = _.get(body, 'mode', 'none');
|
||||
|
||||
if (mode === 'none') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mode === 'graphql') {
|
||||
return {
|
||||
type: 'graphql',
|
||||
query: _.get(body, 'graphql.query', ''),
|
||||
variables: _.get(body, 'graphql.variables', '')
|
||||
};
|
||||
}
|
||||
|
||||
if (mode === 'sparql') {
|
||||
return {
|
||||
type: 'sparql',
|
||||
query: _.get(body, 'sparql', '')
|
||||
};
|
||||
}
|
||||
|
||||
if (mode === 'formUrlEncoded') {
|
||||
return {
|
||||
type: 'form-urlencoded',
|
||||
data: _.map(_.get(body, 'formUrlEncoded', []), (param) => {
|
||||
const paramObj = {
|
||||
name: param.name,
|
||||
value: param.value
|
||||
};
|
||||
|
||||
if (param.description) {
|
||||
paramObj.description = param.description;
|
||||
}
|
||||
|
||||
if (param.enabled === false) {
|
||||
paramObj.disabled = true;
|
||||
}
|
||||
|
||||
return paramObj;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
if (mode === 'multipartForm') {
|
||||
return {
|
||||
type: 'multipart-form',
|
||||
data: _.map(_.get(body, 'multipartForm', []), (param) => {
|
||||
const paramObj = {
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
type: param.type
|
||||
};
|
||||
|
||||
if (param.description) {
|
||||
paramObj.description = param.description;
|
||||
}
|
||||
|
||||
if (param.enabled === false) {
|
||||
paramObj.disabled = true;
|
||||
}
|
||||
|
||||
if (param.contentType) {
|
||||
paramObj.content_type = param.contentType;
|
||||
}
|
||||
|
||||
return paramObj;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
let data = '';
|
||||
switch(mode) {
|
||||
case 'json':
|
||||
data = _.get(body, 'json', '');
|
||||
break;
|
||||
case 'text':
|
||||
data = _.get(body, 'text', '');
|
||||
break;
|
||||
case 'xml':
|
||||
data = _.get(body, 'xml', '');
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
type: mode,
|
||||
data
|
||||
};
|
||||
};
|
||||
|
||||
const getAuth = (req) => {
|
||||
const auth = {};
|
||||
const mode = _.get(req, 'auth.mode', 'none');
|
||||
|
||||
if (req?.auth?.awsv4) {
|
||||
auth.awsv4 = {
|
||||
access_key_id: req?.auth?.awsv4?.accessKeyId,
|
||||
secret_access_key: req?.auth?.awsv4?.secretAccessKey,
|
||||
session_token: req?.auth?.awsv4?.sessionToken,
|
||||
service: req?.auth?.awsv4?.service,
|
||||
region: req?.auth?.awsv4?.region,
|
||||
profile_name: req?.auth?.awsv4?.profileName
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.basic) {
|
||||
auth.basic = {
|
||||
username: req?.auth?.basic?.username,
|
||||
password: req?.auth?.basic?.password
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.bearer) {
|
||||
auth.bearer = {
|
||||
token: req?.auth?.bearer?.token
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.digest) {
|
||||
auth.digest = {
|
||||
username: req?.auth?.digest?.username,
|
||||
password: req?.auth?.digest?.password
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.ntlm) {
|
||||
auth.ntlm = {
|
||||
username: req?.auth?.ntlm?.username,
|
||||
password: req?.auth?.ntlm?.password,
|
||||
domain: req?.auth?.ntlm?.domain
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.oauth2) {
|
||||
auth.oauth2 = {};
|
||||
|
||||
if (req?.auth?.oauth2?.grantType === 'password') {
|
||||
auth.oauth2 = {
|
||||
grant_type: 'password',
|
||||
access_token_url: req?.auth?.oauth2?.accessTokenUrl || '',
|
||||
username: req?.auth?.oauth2?.username || '',
|
||||
password: req?.auth?.oauth2?.password || '',
|
||||
client_id: req?.auth?.oauth2?.clientId || '',
|
||||
client_secret: req?.auth?.oauth2?.clientSecret || '',
|
||||
scope: req?.auth?.oauth2?.scope || ''
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.oauth2?.grantType === 'authorization_code') {
|
||||
auth.oauth2 = {
|
||||
grant_type: 'authorization_code',
|
||||
callback_url: req?.auth?.oauth2?.callbackUrl || '',
|
||||
authorization_url: req?.auth?.oauth2?.authorizationUrl || '',
|
||||
access_token_url: req?.auth?.oauth2?.accessTokenUrl || '',
|
||||
client_id: req?.auth?.oauth2?.clientId || '',
|
||||
client_secret: req?.auth?.oauth2?.clientSecret || '',
|
||||
scope: req?.auth?.oauth2?.scope || '',
|
||||
state: req?.auth?.oauth2?.state || '',
|
||||
pkce: req?.auth?.oauth2?.pkce || false
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.oauth2?.grantType === 'client_credentials') {
|
||||
auth.oauth2 = {
|
||||
grant_type: 'client_credentials',
|
||||
access_token_url: req?.auth?.oauth2?.accessTokenUrl || '',
|
||||
client_id: req?.auth?.oauth2?.clientId || '',
|
||||
client_secret: req?.auth?.oauth2?.clientSecret || '',
|
||||
scope: req?.auth?.oauth2?.scope || ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (req?.auth?.apikey) {
|
||||
auth.apikey = {
|
||||
key: req?.auth?.apikey?.key,
|
||||
value: req?.auth?.apikey?.value,
|
||||
placement: req?.auth?.apikey?.placement
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: mode,
|
||||
...auth
|
||||
};
|
||||
};
|
||||
|
||||
const getVars = (req) => {
|
||||
const preRequest = _.map(_.get(req, 'vars.req', []), (variable) => {
|
||||
const varObj = {
|
||||
name: variable.name,
|
||||
value: variable.value
|
||||
};
|
||||
|
||||
if (variable.description) {
|
||||
varObj.description = variable.description;
|
||||
}
|
||||
|
||||
if (variable.enabled === false) {
|
||||
varObj.disabled = true;
|
||||
}
|
||||
|
||||
return varObj;
|
||||
});
|
||||
|
||||
const postResponse = _.map(_.get(req, 'vars.res', []), (variable) => {
|
||||
const varObj = {
|
||||
name: variable.name,
|
||||
value: variable.value
|
||||
};
|
||||
|
||||
if (variable.description) {
|
||||
varObj.description = variable.description;
|
||||
}
|
||||
|
||||
if (variable.enabled === false) {
|
||||
varObj.disabled = true;
|
||||
}
|
||||
|
||||
return varObj;
|
||||
});
|
||||
|
||||
const vars = {};
|
||||
|
||||
if(preRequest.length) {
|
||||
vars['pre-request'] = preRequest;
|
||||
}
|
||||
|
||||
if(postResponse.length) {
|
||||
vars['post-response'] = postResponse;
|
||||
}
|
||||
|
||||
return !_.isEmpty(vars) ? vars : null;
|
||||
};
|
||||
|
||||
const getScripts = (req) => {
|
||||
const preRequestScript = _.get(req, 'script.req', '');
|
||||
const postResponseScript = _.get(req, 'script.res', '');
|
||||
|
||||
const scripts = {};
|
||||
if (preRequestScript) {
|
||||
scripts['pre-request'] = preRequestScript;
|
||||
}
|
||||
if (postResponseScript) {
|
||||
scripts['post-response'] = postResponseScript;
|
||||
}
|
||||
|
||||
return !_.isEmpty(scripts) ? scripts : null;
|
||||
};
|
||||
|
||||
const getTests = (req) => {
|
||||
return _.get(req, 'tests', '');
|
||||
};
|
||||
|
||||
const getDocs = (req) => {
|
||||
return _.get(req, 'docs', '');
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getMeta,
|
||||
getParams,
|
||||
getHeaders,
|
||||
getBody,
|
||||
getAuth,
|
||||
getVars,
|
||||
getScripts,
|
||||
getTests,
|
||||
getDocs
|
||||
};
|
||||
8
packages/bruno-lang/v3/src/index.js
Normal file
8
packages/bruno-lang/v3/src/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const _ = require('lodash');
|
||||
const stringifyRequest = require('./stringifyRequest');
|
||||
const parseRequest = require('./parseRequest');
|
||||
|
||||
module.exports = {
|
||||
parseRequest,
|
||||
stringifyRequest,
|
||||
};
|
||||
235
packages/bruno-lang/v3/src/parseRequest.js
Normal file
235
packages/bruno-lang/v3/src/parseRequest.js
Normal file
@@ -0,0 +1,235 @@
|
||||
const yaml = require('js-yaml');
|
||||
const _ = require('lodash');
|
||||
|
||||
const parseRequest = (yamlContent) => {
|
||||
const yamlData = yaml.load(yamlContent);
|
||||
const isHttp = !!yamlData.http;
|
||||
const request = isHttp ? yamlData.http : yamlData.graphql;
|
||||
|
||||
const item = {
|
||||
name: yamlData.meta.name,
|
||||
description: yamlData.meta.description || '',
|
||||
seq: yamlData.meta.seq,
|
||||
type: isHttp ? 'http-request' : 'graphql-request'
|
||||
};
|
||||
|
||||
item.request = {
|
||||
method: request.method.toUpperCase(),
|
||||
url: request.url,
|
||||
headers: _.map(request.headers || [], header => ({
|
||||
name: header.name,
|
||||
value: header.value,
|
||||
description: header.description || '',
|
||||
enabled: !header.disabled
|
||||
})),
|
||||
params: _.flatMap(request.params || {}, (params, type) => {
|
||||
return _.map(params, param => ({
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
type,
|
||||
description: param.description || '',
|
||||
enabled: !param.disabled
|
||||
}));
|
||||
}),
|
||||
body: {
|
||||
mode: 'none',
|
||||
json: null,
|
||||
text: null,
|
||||
xml: null,
|
||||
sparql: null,
|
||||
formUrlEncoded: [],
|
||||
multipartForm: [],
|
||||
graphql: null
|
||||
},
|
||||
auth: {
|
||||
mode: 'none',
|
||||
awsv4: null,
|
||||
basic: null,
|
||||
bearer: null,
|
||||
ntlm: null,
|
||||
digest: null,
|
||||
oauth2: null,
|
||||
wsse: null,
|
||||
apikey: null
|
||||
},
|
||||
vars: {
|
||||
req: [],
|
||||
res: []
|
||||
},
|
||||
script: {
|
||||
req: '',
|
||||
res: ''
|
||||
},
|
||||
tests: '',
|
||||
docs: ''
|
||||
};
|
||||
|
||||
// Handle body
|
||||
if (request.body) {
|
||||
item.request.body.mode = request.body.type;
|
||||
switch(request.body.type) {
|
||||
case 'json':
|
||||
item.request.body.json = request.body.data;
|
||||
break;
|
||||
case 'text':
|
||||
item.request.body.text = request.body.data;
|
||||
break;
|
||||
case 'xml':
|
||||
item.request.body.xml = request.body.data;
|
||||
break;
|
||||
case 'sparql':
|
||||
item.request.body.sparql = request.body.data;
|
||||
break;
|
||||
case 'formUrlEncoded':
|
||||
item.request.body.formUrlEncoded = _.map(request.body.data, formItem => ({
|
||||
name: formItem.name,
|
||||
value: formItem.value,
|
||||
description: formItem.description || '',
|
||||
enabled: !formItem.disabled
|
||||
}));
|
||||
break;
|
||||
case 'multipartForm':
|
||||
item.request.body.multipartForm = _.map(request.body.data, formItem => ({
|
||||
name: formItem.name,
|
||||
value: formItem.value,
|
||||
description: formItem.description || '',
|
||||
enabled: !formItem.disabled,
|
||||
contentType: formItem.content_type || ''
|
||||
}));
|
||||
break;
|
||||
case 'graphql':
|
||||
item.request.body.graphql = {
|
||||
query: request.body.data.query || '',
|
||||
variables: request.body.data.variables || ''
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle auth
|
||||
if (request.auth) {
|
||||
item.request.auth.mode = request.auth.type;
|
||||
|
||||
switch(request.auth.type) {
|
||||
case 'awsv4':
|
||||
item.request.auth.awsv4 = {
|
||||
accessKeyId: request.auth.access_key_id,
|
||||
secretAccessKey: request.auth.secret_access_key,
|
||||
sessionToken: request.auth.session_token,
|
||||
service: request.auth.service,
|
||||
region: request.auth.region,
|
||||
profileName: request.auth.profile_name
|
||||
}
|
||||
break;
|
||||
case 'basic':
|
||||
item.request.auth.basic = {
|
||||
username: request.auth.username,
|
||||
password: request.auth.password
|
||||
}
|
||||
break;
|
||||
case 'bearer':
|
||||
item.request.auth.bearer = {
|
||||
token: request.auth.token
|
||||
}
|
||||
break;
|
||||
case 'digest':
|
||||
item.request.auth.digest = {
|
||||
username: request.auth.username,
|
||||
password: request.auth.password
|
||||
}
|
||||
break;
|
||||
case 'ntlm':
|
||||
item.request.auth.ntlm = {
|
||||
username: request.auth.username,
|
||||
password: request.auth.password,
|
||||
domain: request.auth.domain
|
||||
}
|
||||
break;
|
||||
case 'wsse':
|
||||
item.request.auth.wsse = {
|
||||
username: request.auth.username,
|
||||
password: request.auth.password
|
||||
}
|
||||
break;
|
||||
case 'apikey':
|
||||
item.request.auth.apikey = {
|
||||
key: request.auth.key,
|
||||
value: request.auth.value,
|
||||
placement: request.auth.placement
|
||||
}
|
||||
break;
|
||||
case 'oauth2':
|
||||
if (request.auth.grant_type === 'password') {
|
||||
item.request.auth.oauth2 = {
|
||||
grantType: 'password',
|
||||
accessTokenUrl: request.auth.access_token_url || '',
|
||||
clientId: request.auth.client_id || '',
|
||||
clientSecret: request.auth.client_secret || '',
|
||||
scope: request.auth.scope || '',
|
||||
username: request.auth.username || '',
|
||||
password: request.auth.password || ''
|
||||
};
|
||||
} else if (request.auth.grant_type === 'authorization_code') {
|
||||
item.request.auth.oauth2 = {
|
||||
grantType: 'authorization_code',
|
||||
accessTokenUrl: request.auth.access_token_url || '',
|
||||
clientId: request.auth.client_id || '',
|
||||
clientSecret: request.auth.client_secret || '',
|
||||
scope: request.auth.scope || '',
|
||||
callbackUrl: request.auth.callback_url || '',
|
||||
authorizationUrl: request.auth.authorization_url || '',
|
||||
state: request.auth.state || '',
|
||||
pkce: request.auth.pkce || false
|
||||
};
|
||||
} else if (request.auth.grant_type === 'client_credentials') {
|
||||
item.request.auth.oauth2 = {
|
||||
grantType: 'client_credentials',
|
||||
accessTokenUrl: request.auth.access_token_url || '',
|
||||
clientId: request.auth.client_id || '',
|
||||
clientSecret: request.auth.client_secret || '',
|
||||
scope: request.auth.scope || ''
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle vars
|
||||
if (yamlData.vars) {
|
||||
item.request.vars = {
|
||||
req: _.map(yamlData.vars['pre-request'] || [], v => ({
|
||||
name: v.name,
|
||||
value: v.value,
|
||||
description: v.description || '',
|
||||
enabled: !v.disabled
|
||||
})),
|
||||
res: _.map(yamlData.vars['post-response'] || [], v => ({
|
||||
name: v.name,
|
||||
value: v.value,
|
||||
description: v.description || '',
|
||||
enabled: !v.disabled
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
// Handle scripts
|
||||
if (yamlData.scripts) {
|
||||
item.request.script = {
|
||||
req: yamlData.scripts['pre-request'] || '',
|
||||
res: yamlData.scripts['post-response'] || ''
|
||||
};
|
||||
}
|
||||
|
||||
// Handle tests and docs
|
||||
if (yamlData.tests) {
|
||||
item.request.tests = yamlData.tests;
|
||||
}
|
||||
|
||||
if (yamlData.docs) {
|
||||
item.request.docs = yamlData.docs;
|
||||
}
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
module.exports = parseRequest;
|
||||
54
packages/bruno-lang/v3/src/stringifyRequest.js
Normal file
54
packages/bruno-lang/v3/src/stringifyRequest.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const yaml = require('js-yaml');
|
||||
const _ = require('lodash');
|
||||
const { getMeta, getParams, getHeaders, getVars, getScripts, getBody, getAuth, getTests, getDocs } = require('./common');
|
||||
|
||||
const stringifyRequest = (json) => {
|
||||
const request = json?.request;
|
||||
const requestBody = getBody(request);
|
||||
const requestAuth = getAuth(request);
|
||||
const isGraphql = requestBody?.type === 'graphql';
|
||||
|
||||
const requestData = {
|
||||
method: _.lowerCase(_.get(json, 'request.method')),
|
||||
url: _.get(json, 'request.url'),
|
||||
params: getParams(request),
|
||||
headers: getHeaders(request),
|
||||
};
|
||||
|
||||
if (requestBody && requestBody.type !== 'none') {
|
||||
requestData.body = requestBody;
|
||||
}
|
||||
|
||||
if (requestAuth && requestAuth.mode !== 'none') {
|
||||
requestData.auth = requestAuth;
|
||||
}
|
||||
|
||||
const finalJson = {
|
||||
meta: getMeta(json),
|
||||
[isGraphql ? 'graphql' : 'http']: requestData
|
||||
};
|
||||
|
||||
const vars = getVars(request);
|
||||
if (vars) {
|
||||
finalJson.vars = vars;
|
||||
}
|
||||
|
||||
const scripts = getScripts(request);
|
||||
if (scripts) {
|
||||
finalJson.scripts = scripts;
|
||||
}
|
||||
|
||||
const tests = getTests(request);
|
||||
if (tests) {
|
||||
finalJson.tests = tests;
|
||||
}
|
||||
|
||||
const docs = getDocs(request);
|
||||
if (docs) {
|
||||
finalJson.docs = docs;
|
||||
}
|
||||
|
||||
return yaml.dump(finalJson);
|
||||
};
|
||||
|
||||
module.exports = stringifyRequest;
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "Get User GraphQL",
|
||||
"seq": 1,
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.example.com/graphql",
|
||||
"headers": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "graphql",
|
||||
"graphql": {
|
||||
"query": "query GetUser($id: ID!) {\n user(id: $id) {\n id\n name\n email\n }\n}",
|
||||
"variables": "{\n \"id\": \"123\"\n}"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"mode": "bearer",
|
||||
"bearer": {
|
||||
"token": "jwt-token"
|
||||
}
|
||||
},
|
||||
"vars": {
|
||||
"req": [
|
||||
{
|
||||
"name": "userId",
|
||||
"value": "123"
|
||||
}
|
||||
]
|
||||
},
|
||||
"script": {
|
||||
"req": "// Pre-request script for GraphQL"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
meta:
|
||||
name: Get User GraphQL
|
||||
seq: 1
|
||||
graphql:
|
||||
method: post
|
||||
url: https://api.example.com/graphql
|
||||
params:
|
||||
query: []
|
||||
path: []
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: graphql
|
||||
query: |-
|
||||
query GetUser($id: ID!) {
|
||||
user(id: $id) {
|
||||
id
|
||||
name
|
||||
email
|
||||
}
|
||||
}
|
||||
variables: |-
|
||||
{
|
||||
"id": "123"
|
||||
}
|
||||
auth:
|
||||
type: bearer
|
||||
bearer:
|
||||
token: jwt-token
|
||||
vars:
|
||||
pre-request:
|
||||
- name: userId
|
||||
value: '123'
|
||||
scripts:
|
||||
pre-request: // Pre-request script for GraphQL
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "HTTP Methods",
|
||||
"seq": 1,
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.example.com/users",
|
||||
"headers": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Content type header",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Accept",
|
||||
"value": "application/json",
|
||||
"enabled": false
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"name": "userId",
|
||||
"value": "123",
|
||||
"type": "path",
|
||||
"description": "User ID parameter",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "filter",
|
||||
"value": "active",
|
||||
"type": "query",
|
||||
"enabled": false
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "json",
|
||||
"json": "{\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n}"
|
||||
},
|
||||
"auth": {
|
||||
"mode": "basic",
|
||||
"basic": {
|
||||
"username": "admin",
|
||||
"password": "secret"
|
||||
}
|
||||
},
|
||||
"vars": {
|
||||
"req": [
|
||||
{
|
||||
"name": "userId",
|
||||
"value": "123",
|
||||
"description": "User ID variable",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"res": [
|
||||
{
|
||||
"name": "token",
|
||||
"value": "response.token",
|
||||
"enabled": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"script": {
|
||||
"req": "// Pre-request script\nconsole.log('pre-request');",
|
||||
"res": "// Post-response script\nconsole.log('post-response');"
|
||||
},
|
||||
"tests": "// Test script\nassert.response.status === 200;",
|
||||
"docs": "# User Creation API\nThis endpoint creates a new user."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
meta:
|
||||
name: HTTP Methods
|
||||
seq: 1
|
||||
http:
|
||||
method: post
|
||||
url: https://api.example.com/users
|
||||
params:
|
||||
query:
|
||||
- name: filter
|
||||
value: active
|
||||
type: query
|
||||
disabled: true
|
||||
path:
|
||||
- name: userId
|
||||
value: '123'
|
||||
type: path
|
||||
description: User ID parameter
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
description: Content type header
|
||||
- name: Accept
|
||||
value: application/json
|
||||
disabled: true
|
||||
body:
|
||||
type: json
|
||||
data: |-
|
||||
{
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com"
|
||||
}
|
||||
auth:
|
||||
type: basic
|
||||
basic:
|
||||
username: admin
|
||||
password: secret
|
||||
vars:
|
||||
pre-request:
|
||||
- name: userId
|
||||
value: '123'
|
||||
description: User ID variable
|
||||
post-response:
|
||||
- name: token
|
||||
value: response.token
|
||||
disabled: true
|
||||
scripts:
|
||||
pre-request: |-
|
||||
// Pre-request script
|
||||
console.log('pre-request');
|
||||
post-response: |-
|
||||
// Post-response script
|
||||
console.log('post-response');
|
||||
tests: |-
|
||||
// Test script
|
||||
assert.response.status === 200;
|
||||
docs: |-
|
||||
# User Creation API
|
||||
This endpoint creates a new user.
|
||||
103
packages/bruno-lang/v3/tests/stringifyRequest/graphql.test.js
Normal file
103
packages/bruno-lang/v3/tests/stringifyRequest/graphql.test.js
Normal file
@@ -0,0 +1,103 @@
|
||||
const { stringifyRequest } = require('../../src');
|
||||
const yaml = require('js-yaml');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
describe('GraphQL Request Handling', () => {
|
||||
const loadFixture = (filename) => {
|
||||
const filePath = path.join(__dirname, '__fixtures__', filename);
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
};
|
||||
|
||||
it('should generate exact YAML matching the fixture', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
const expectedYaml = fs.readFileSync(
|
||||
path.join(__dirname, '__fixtures__', 'graphql-request.yml'),
|
||||
'utf8'
|
||||
);
|
||||
const generatedYaml = stringifyRequest(json);
|
||||
|
||||
// Normalize line endings and whitespace for comparison
|
||||
const normalizeString = (str) => str.replace(/\r\n/g, '\n').trim();
|
||||
expect(normalizeString(generatedYaml)).toBe(normalizeString(expectedYaml));
|
||||
});
|
||||
|
||||
it('should correctly format GraphQL request', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
// Verify GraphQL section exists instead of HTTP
|
||||
expect(result.graphql).toBeDefined();
|
||||
expect(result.http).toBeUndefined();
|
||||
|
||||
// Verify basic properties
|
||||
expect(result.graphql.method).toBe('post');
|
||||
expect(result.graphql.url).toBe('https://api.example.com/graphql');
|
||||
|
||||
// Verify headers
|
||||
expect(result.graphql.headers).toHaveLength(1);
|
||||
expect(result.graphql.headers[0]).toEqual({
|
||||
name: 'Content-Type',
|
||||
value: 'application/json'
|
||||
});
|
||||
|
||||
// Verify body
|
||||
expect(result.graphql.body).toEqual({
|
||||
type: 'graphql',
|
||||
query: 'query GetUser($id: ID!) {\n user(id: $id) {\n id\n name\n email\n }\n}',
|
||||
variables: '{\n \"id\": \"123\"\n}'
|
||||
});
|
||||
|
||||
// Verify auth
|
||||
expect(result.graphql.auth).toEqual({
|
||||
type: 'bearer',
|
||||
bearer: {
|
||||
token: 'jwt-token'
|
||||
}
|
||||
});
|
||||
|
||||
// Verify vars
|
||||
expect(result.vars['pre-request']).toHaveLength(1);
|
||||
expect(result.vars['pre-request'][0]).toEqual({
|
||||
name: 'userId',
|
||||
value: '123'
|
||||
});
|
||||
|
||||
// Verify scripts
|
||||
expect(result.scripts['pre-request']).toBe('// Pre-request script for GraphQL');
|
||||
});
|
||||
|
||||
it('should handle GraphQL request without variables', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
json.request.body.graphql.variables = '';
|
||||
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
expect(result.graphql.body.variables).toBe('');
|
||||
});
|
||||
|
||||
it('should handle GraphQL request without optional components', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
|
||||
// Remove optional components
|
||||
delete json.request.auth;
|
||||
delete json.request.vars;
|
||||
delete json.request.script;
|
||||
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.graphql.auth).toEqual({ type: 'none' });
|
||||
expect(result.vars).toBeUndefined();
|
||||
expect(result.scripts).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should detect GraphQL request based on body mode', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
|
||||
// Change URL but keep GraphQL body
|
||||
json.request.url = 'https://api.example.com/not-graphql';
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.graphql).toBeDefined();
|
||||
expect(result.http).toBeUndefined();
|
||||
});
|
||||
});
|
||||
244
packages/bruno-lang/v3/tests/stringifyRequest/http.test.js
Normal file
244
packages/bruno-lang/v3/tests/stringifyRequest/http.test.js
Normal file
@@ -0,0 +1,244 @@
|
||||
const { stringifyRequest } = require('../../src');
|
||||
const yaml = require('js-yaml');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
describe('HTTP Request Handling', () => {
|
||||
const loadFixture = (filename) => {
|
||||
const filePath = path.join(__dirname, '__fixtures__', filename);
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
};
|
||||
|
||||
it('should generate exact YAML matching the fixture', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const expectedYaml = fs.readFileSync(
|
||||
path.join(__dirname, '__fixtures__', 'http-request.yml'),
|
||||
'utf8'
|
||||
);
|
||||
const generatedYaml = stringifyRequest(json);
|
||||
|
||||
// Normalize line endings and whitespace for comparison
|
||||
const normalizeString = (str) => str.replace(/\r\n/g, '\n').trim();
|
||||
expect(normalizeString(generatedYaml)).toBe(normalizeString(expectedYaml));
|
||||
});
|
||||
|
||||
it('should correctly format basic HTTP request', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
// Verify HTTP section exists instead of GraphQL
|
||||
expect(result.http).toBeDefined();
|
||||
expect(result.graphql).toBeUndefined();
|
||||
|
||||
// Verify basic properties
|
||||
expect(result.meta.name).toBe('HTTP Methods');
|
||||
expect(result.meta.seq).toBe(1);
|
||||
expect(result.http.method).toBe('post');
|
||||
expect(result.http.url).toBe('https://api.example.com/users');
|
||||
});
|
||||
|
||||
it('should handle request with query parameters', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.params.query).toEqual([
|
||||
{
|
||||
name: 'filter',
|
||||
value: 'active',
|
||||
type: 'query',
|
||||
disabled: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle request with path parameters', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.params.path).toEqual([
|
||||
{
|
||||
name: 'userId',
|
||||
value: '123',
|
||||
type: 'path',
|
||||
description: 'User ID parameter'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle request with headers', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.headers).toEqual([
|
||||
{
|
||||
name: 'Content-Type',
|
||||
value: 'application/json',
|
||||
description: 'Content type header'
|
||||
},
|
||||
{
|
||||
name: 'Accept',
|
||||
value: 'application/json',
|
||||
disabled: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
describe('Body Handling', () => {
|
||||
it('should handle JSON body', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.body).toEqual({
|
||||
type: 'json',
|
||||
data: '{\n "name": "John Doe",\n "email": "john@example.com"\n}'
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle form-urlencoded body', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.body = {
|
||||
mode: 'formUrlEncoded',
|
||||
formUrlEncoded: [
|
||||
{ name: 'username', value: 'johndoe', description: 'Username field', enabled: true },
|
||||
{ name: 'password', value: 'secret', enabled: false }
|
||||
]
|
||||
};
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.body).toEqual({
|
||||
type: 'form-urlencoded',
|
||||
data: [
|
||||
{ name: 'username', value: 'johndoe', description: 'Username field' },
|
||||
{ name: 'password', value: 'secret', disabled: true }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multipart-form body', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.body = {
|
||||
mode: 'multipartForm',
|
||||
multipartForm: [
|
||||
{ name: 'file', value: ['path/to/file'], type: 'file', enabled: true },
|
||||
{ name: 'description', value: 'profile photo', type: 'text', enabled: true }
|
||||
]
|
||||
};
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.body).toEqual({
|
||||
type: 'multipart-form',
|
||||
data: [
|
||||
{ name: 'file', value: ['path/to/file'], type: 'file' },
|
||||
{ name: 'description', value: 'profile photo', type: 'text' }
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Auth Handling', () => {
|
||||
it('should handle basic auth', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.auth).toEqual({
|
||||
type: 'basic',
|
||||
basic: {
|
||||
username: 'admin',
|
||||
password: 'secret'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle bearer auth', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.auth = {
|
||||
mode: 'bearer',
|
||||
bearer: { token: 'xyz123' }
|
||||
};
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.auth).toEqual({
|
||||
type: 'bearer',
|
||||
bearer: {
|
||||
token: 'xyz123'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle oauth2 password grant', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.auth = {
|
||||
mode: 'oauth2',
|
||||
oauth2: {
|
||||
grantType: 'password',
|
||||
accessTokenUrl: 'https://api.example.com/oauth/token',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
clientId: 'client123',
|
||||
clientSecret: 'secret123',
|
||||
scope: 'read write'
|
||||
}
|
||||
};
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.auth).toEqual({
|
||||
type: 'oauth2',
|
||||
oauth2: {
|
||||
grant_type: 'password',
|
||||
access_token_url: 'https://api.example.com/oauth/token',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
client_id: 'client123',
|
||||
client_secret: 'secret123',
|
||||
scope: 'read write'
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variables and Scripts', () => {
|
||||
it('should handle pre-request variables', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.vars['pre-request']).toEqual([
|
||||
{ name: 'userId', value: '123', description: 'User ID variable' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle post-response variables', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.vars['post-response']).toEqual([
|
||||
{ name: 'token', value: 'response.token', disabled: true }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle scripts', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.scripts['pre-request']).toBe('// Pre-request script\nconsole.log(\'pre-request\');');
|
||||
expect(result.scripts['post-response']).toBe('// Post-response script\nconsole.log(\'post-response\');');
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle tests and docs', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.tests).toBe('// Test script\nassert.response.status === 200;');
|
||||
expect(result.docs).toBe('# User Creation API\nThis endpoint creates a new user.');
|
||||
});
|
||||
|
||||
it('should handle disabled components', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.headers[0].enabled = false;
|
||||
json.request.params[0].enabled = false;
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.headers[0].disabled).toBe(true);
|
||||
expect(result.http.params.query[0].disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -41,7 +41,7 @@ const varsSchema = Yup.object({
|
||||
|
||||
// todo
|
||||
// anoop(4 feb 2023) - nobody uses this, and it needs to be removed
|
||||
local: Yup.boolean()
|
||||
local: Yup.boolean().optional()
|
||||
})
|
||||
.noUnknown(true)
|
||||
.strict();
|
||||
@@ -298,9 +298,10 @@ const folderRootSchema = Yup.object({
|
||||
|
||||
const itemSchema = Yup.object({
|
||||
uid: uidSchema,
|
||||
name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'),
|
||||
description: Yup.string().nullable(),
|
||||
type: Yup.string().oneOf(['http-request', 'graphql-request', 'folder', 'js']).required('type is required'),
|
||||
seq: Yup.number().min(1),
|
||||
name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'),
|
||||
request: requestSchema.when('type', {
|
||||
is: (type) => ['http-request', 'graphql-request'].includes(type),
|
||||
then: (schema) => schema.required('request is required when item-type is request')
|
||||
|
||||
Reference in New Issue
Block a user