Skip to content

Commit 8f11f1d

Browse files
committed
CLOUDP-298233: postman transformation in js
1 parent 558329f commit 8f11f1d

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

tools/postman/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ convert_to_collection:
1717
transform_collection:
1818
./scripts/transform-for-api.sh
1919

20+
.PHONY: transform_collection_js
21+
transform_collection_js:
22+
node ./scripts/transform-postman.cjs
23+
2024
.PHONY: transform_collection_test
2125
transform_collection_test:
2226
./scripts/transform-for-api-test.sh
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const _ = require('lodash');
4+
5+
/**
6+
# Prepare collection for Postman API
7+
# Environment variables:
8+
# COLLECTION_FILE_NAME - name of the postman collection file
9+
# COLLECTION_TRANSFORMED_FILE_NAME - name of the transformed collection file
10+
# OPENAPI_FILE_NAME - name of the openapi specification file
11+
# OPENAPI_FOLDER - folder where openapi file is saved
12+
# TMP_FOLDER - folder for temporary files during transformations
13+
# VERSION_FILE_NAME - name of the file where the current version is stored
14+
# DESCRIPTION_FILE - name for the markdown description file
15+
# TOGGLE_INCLUDE_BODY - bool for if generated bodies should be removed or kept
16+
# TOGGLE_ADD_DOCS_LINKS - updates requests with corresponding docs links
17+
# TOKEN_URL_ENV - client credentials auth path to set at the environment level, will not be set if unpopulated
18+
# BASE_URL - the default base url the Postman Collection will use
19+
*/
20+
// TODO CLI arguments instead of env variables.
21+
const COLLECTION_FILE_NAME = process.env.COLLECTION_FILE_NAME || 'collection.json';
22+
const COLLECTION_TRANSFORMED_FILE_NAME = process.env.COLLECTION_TRANSFORMED_FILE_NAME || 'collection-transformed.json';
23+
const OPENAPI_FILE_NAME = process.env.OPENAPI_FILE_NAME || 'atlas-api.json';
24+
const OPENAPI_FOLDER = process.env.OPENAPI_FOLDER || './openapi';
25+
const TMP_FOLDER = process.env.TMP_FOLDER || './tmp';
26+
const VERSION_FILE_NAME = process.env.VERSION_FILE_NAME || 'version.txt';
27+
const DESCRIPTION_FILE = process.env.DESCRIPTION_FILE || './collection-description.md';
28+
const TOGGLE_INCLUDE_BODY = process.env.TOGGLE_INCLUDE_BODY !== 'false';
29+
const TOGGLE_ADD_DOCS_LINKS = process.env.TOGGLE_ADD_DOCS_LINKS === 'true';
30+
const TOKEN_URL_ENV = process.env.TOKEN_URL_ENV || '';
31+
const BASE_URL = process.env.BASE_URL || '';
32+
33+
// Dedicated transformation for postman collection.json file.
34+
const transform = () => {
35+
const currentApiRevision = fs.readFileSync(path.join(OPENAPI_FOLDER, VERSION_FILE_NAME), 'utf8').trim();
36+
let collection = loadJsonFile(path.join(TMP_FOLDER, COLLECTION_FILE_NAME));
37+
38+
console.log(`Wrapping Collection ${COLLECTION_FILE_NAME} in "collection" tag`);
39+
collection = { collection };
40+
41+
console.log('Disabling query params by default');
42+
_.forEach(collection.collection.item, (item) => {
43+
if (item.request && item.request.url && Array.isArray(item.request.url.query)) {
44+
item.request.url.query.forEach((query) => {
45+
query.disabled = true;
46+
});
47+
}
48+
});
49+
50+
console.log('Removing _postman_id');
51+
delete collection.collection.info._postman_id;
52+
53+
console.log('Removing circular references');
54+
const collectionString = JSON.stringify(collection);
55+
const cleanedCollectionString = removeCircularReferences(collectionString);
56+
collection = JSON.parse(cleanedCollectionString);
57+
58+
console.log(`Updating name with version ${currentApiRevision}`);
59+
collection.collection.info.name = `MongoDB Atlas Administration API ${currentApiRevision}`;
60+
61+
console.log('Adding Collection description');
62+
const description = fs.readFileSync(DESCRIPTION_FILE, 'utf8').trim();
63+
_.set(collection, 'collection.info.description.content', description);
64+
65+
console.log('Removing all variables. We use environment for variables instead');
66+
collection.collection.variable = [];
67+
68+
console.log(`Adding baseUrl property ${BASE_URL}`);
69+
collection.collection.variable.push({ key: 'baseUrl', value: BASE_URL });
70+
71+
if (TOGGLE_ADD_DOCS_LINKS) {
72+
console.log('Adding links to docs for each request');
73+
74+
const openapiContent = loadJsonFile(path.join(OPENAPI_FOLDER, OPENAPI_FILE_NAME));
75+
const paths = _.keys(openapiContent.paths);
76+
77+
paths.forEach((pathKey) => {
78+
const methods = _.keys(openapiContent.paths[pathKey]);
79+
methods.forEach((method) => {
80+
const requestInfo = openapiContent.paths[pathKey][method];
81+
const title = requestInfo.summary;
82+
const operationId = requestInfo.operationId;
83+
const tag = _.kebabCase(requestInfo.tags[0]);
84+
85+
const url = `https://mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/${tag}/operation/${operationId}`;
86+
87+
const requestItem = _.find(_.flatten(collection.collection.item.map((i) => i.item)), { name: title });
88+
if (requestItem && requestItem.description && requestItem.description.content) {
89+
requestItem.description.content += `\n\nFind out more at ${url}`;
90+
}
91+
});
92+
});
93+
}
94+
95+
if (!TOGGLE_INCLUDE_BODY) {
96+
console.log('Removing generated bodies');
97+
_.forEach(_.flatten(collection.collection.item.map((i) => i.item)), (item) => {
98+
if (item.response) {
99+
item.response.forEach((response) => {
100+
response.body = '';
101+
});
102+
item.request.body = {};
103+
}
104+
});
105+
}
106+
107+
if (TOKEN_URL_ENV) {
108+
console.log(`Adding client credentials auth url variable ${TOKEN_URL_ENV}`);
109+
collection.collection.variable.push({ key: 'clientCredentialsTokenUrl', value: TOKEN_URL_ENV });
110+
}
111+
112+
113+
saveJsonFile(path.join(TMP_FOLDER, COLLECTION_TRANSFORMED_FILE_NAME), collection);
114+
115+
console.log('Transformation complete');
116+
};
117+
118+
function loadJsonFile(filePath) {
119+
const data = fs.readFileSync(filePath, 'utf8');
120+
return JSON.parse(data);
121+
}
122+
123+
function saveJsonFile(filePath, json) {
124+
fs.writeFileSync(filePath, JSON.stringify(json, null, 2), 'utf8');
125+
}
126+
127+
// hack
128+
function removeCircularReferences(jsonStr) {
129+
return jsonStr.replace(/\\"value\\": \\"<Circular reference to #[^>"]* detected>\\"/g, '');
130+
}
131+
132+
transform();

0 commit comments

Comments
 (0)