Skip to content

Commit 602392e

Browse files
taban03achmelo
andauthored
feat: Add customized code snippets to API Catalog (#2526)
* Add customized code snippets Signed-off-by: at670475 <andrea.tabone@broadcom.com> * snippets fix Signed-off-by: achmelo <a.chmelo@gmail.com> * remove log Signed-off-by: achmelo <a.chmelo@gmail.com> * Remove useless eslint statement Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Fix and add new test Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Clean up of code Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Fix code smell Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Add tests Signed-off-by: at670475 <andrea.tabone@broadcom.com> * remove unused config Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Provide better snippet sample Signed-off-by: at670475 <andrea.tabone@broadcom.com> Co-authored-by: achmelo <a.chmelo@gmail.com>
1 parent c990c4c commit 602392e

File tree

9 files changed

+829
-265
lines changed

9 files changed

+829
-265
lines changed

api-catalog-services/src/main/resources/application.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,6 @@ eureka:
144144
version: 1.0.0
145145
gatewayUrl: api/v1
146146
swaggerUrl: https://${apiml.service.hostname}:${apiml.service.port}${apiml.service.contextPath}/v3/api-docs
147-
codeSnippet:
148-
- endpoint: "/greetings"
149-
codeBlock: |
150-
```
151-
System. out. println("Hello, World!");
152-
```
153-
language: java
154147

155148
service:
156149
title: API Catalog

api-catalog-ui/frontend/mocked-backend/assets/containers.json

Lines changed: 448 additions & 156 deletions
Large diffs are not rendered by default.

api-catalog-ui/frontend/mocked-backend/assets/services/cademoapps.json

Lines changed: 105 additions & 52 deletions
Large diffs are not rendered by default.

api-catalog-ui/frontend/src/components/ServiceTab/ServiceTab.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export default class ServiceTab extends Component {
5252
selectedTile,
5353
selectService,
5454
} = this.props;
55-
5655
tiles[0].services.forEach((service) => {
5756
if (service.serviceId === serviceId) {
5857
if (service.serviceId !== selectedService.serviceId || selectedTile !== tileID) {

api-catalog-ui/frontend/src/components/Swagger/SwaggerUI.jsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import SwaggerUi from 'swagger-ui-react';
1313
import './Swagger.css';
1414
import InstanceInfo from '../ServiceTab/InstanceInfo';
1515
import getBaseUrl from '../../helpers/urls';
16-
import { BasicSnippedGenerator } from '../../utils/generateSnippets';
16+
import { CustomizedSnippedGenerator } from '../../utils/generateSnippets';
1717
import { AdvancedFilterPlugin } from '../../utils/filterApis';
1818

1919
function transformSwaggerToCurrentHost(swagger) {
@@ -96,6 +96,9 @@ export default class SwaggerUI extends Component {
9696

9797
setSwaggerState = () => {
9898
const { selectedService, selectedVersion } = this.props;
99+
const codeSnippets =
100+
selectedService.apis[selectedVersion || selectedService.defaultApiVersion].codeSnippet ||
101+
selectedService.apis.default.codeSnippet;
99102
try {
100103
// If no version selected use the default apiDoc
101104
if (
@@ -113,7 +116,7 @@ export default class SwaggerUI extends Component {
113116
spec: swagger,
114117
presets: [SwaggerUi.presets.apis],
115118
requestSnippetsEnabled: true,
116-
plugins: [this.customPlugins, BasicSnippedGenerator, AdvancedFilterPlugin],
119+
plugins: [this.customPlugins, AdvancedFilterPlugin, CustomizedSnippedGenerator(codeSnippets)],
117120
filter: true,
118121
},
119122
});
@@ -128,7 +131,7 @@ export default class SwaggerUI extends Component {
128131
url,
129132
presets: [SwaggerUi.presets.apis],
130133
requestSnippetsEnabled: true,
131-
plugins: [this.customPlugins, BasicSnippedGenerator, AdvancedFilterPlugin],
134+
plugins: [this.customPlugins, AdvancedFilterPlugin, CustomizedSnippedGenerator(codeSnippets)],
132135
filter: true,
133136
responseInterceptor: (res) => {
134137
// response.text field is used to render the swagger

api-catalog-ui/frontend/src/components/Swagger/SwaggerUI.test.jsx

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ describe('>>> Swagger component tests', () => {
2828
basePath: '/enabler/api/v1',
2929
apiDoc: null,
3030
};
31+
service.apis = {
32+
codeSnippet: {
33+
codeBlock: 'code',
34+
endpoint: '/test',
35+
language: 'java',
36+
},
37+
};
3138
const wrapper = shallow(
3239
<div>
3340
<SwaggerUI selectedService={service} />
@@ -47,8 +54,18 @@ describe('>>> Swagger component tests', () => {
4754
secured: false,
4855
homePageUrl: 'http://localhost:10013/enabler/',
4956
basePath: '/enabler/api/v1',
57+
defaultApiVersion: 0,
5058
};
51-
59+
service.apis = [
60+
{
61+
default: { apiId: 'enabler' },
62+
codeSnippet: {
63+
codeBlock: 'code',
64+
endpoint: '/test',
65+
language: 'java',
66+
},
67+
},
68+
];
5269
const container = document.createElement('div');
5370
document.body.appendChild(container);
5471

@@ -71,10 +88,27 @@ describe('>>> Swagger component tests', () => {
7188
servers: [{ url: `https://bad.com${endpoint}` }],
7289
}),
7390
apis: {
74-
default: { apiId: 'enabler' },
91+
default: {
92+
apiId: 'enabler',
93+
codeSnippet: {
94+
codeBlock: 'code',
95+
endpoint: '/test',
96+
language: 'java',
97+
},
98+
},
7599
},
100+
defaultApiVersion: 0,
76101
};
77-
102+
service.apis = [
103+
{
104+
default: { apiId: 'enabler' },
105+
codeSnippet: {
106+
codeBlock: 'code',
107+
endpoint: '/test',
108+
language: 'java',
109+
},
110+
},
111+
];
78112
const container = document.createElement('div');
79113
document.body.appendChild(container);
80114

@@ -100,8 +134,18 @@ describe('>>> Swagger component tests', () => {
100134
apis: {
101135
default: { apiId: 'oldenabler' },
102136
},
137+
defaultApiVersion: 0,
103138
};
104-
139+
service1.apis = [
140+
{
141+
default: { apiId: 'enabler' },
142+
codeSnippet: {
143+
codeBlock: 'code',
144+
endpoint: '/test',
145+
language: 'java',
146+
},
147+
},
148+
];
105149
const service2 = {
106150
serviceId: 'newservice',
107151
title: 'Spring Boot Enabler Service',
@@ -117,8 +161,19 @@ describe('>>> Swagger component tests', () => {
117161
apis: {
118162
default: { apiId: 'oldenabler' },
119163
},
164+
defaultApiVersion: 0,
120165
};
121166

167+
service2.apis = [
168+
{
169+
default: { apiId: 'enabler' },
170+
codeSnippet: {
171+
codeBlock: 'code2',
172+
endpoint: '/test2',
173+
language: 'python',
174+
},
175+
},
176+
];
122177
const container = document.createElement('div');
123178
document.body.appendChild(container);
124179

@@ -127,4 +182,40 @@ describe('>>> Swagger component tests', () => {
127182
await act(async () => render(<SwaggerUI selectedService={service2} />, container));
128183
expect(container.textContent).toContain(`Servershttp://localhost${endpoint2}`);
129184
});
185+
186+
it('should get snippet from selectedVersion and render swagger', async () => {
187+
const endpoint1 = '/oldenabler/api/v1';
188+
const service1 = {
189+
serviceId: 'oldservice',
190+
title: 'Spring Boot Enabler Service',
191+
description: 'Dummy Service for enabling others',
192+
status: 'UP',
193+
secured: false,
194+
homePageUrl: 'http://localhost:10013/oldenabler/',
195+
basePath: '/oldenabler/api/v1',
196+
apiDoc: JSON.stringify({
197+
openapi: '3.0.0',
198+
servers: [{ url: `https://bad.com${endpoint1}` }],
199+
}),
200+
apis: {
201+
default: { apiId: 'oldenabler' },
202+
},
203+
defaultApiVersion: 0,
204+
};
205+
service1.apis = [
206+
{
207+
default: { apiId: 'enabler' },
208+
},
209+
];
210+
service1.apis[0].codeSnippet = {
211+
codeBlock: 'code',
212+
endpoint: '/test',
213+
language: 'java',
214+
};
215+
const container = document.createElement('div');
216+
document.body.appendChild(container);
217+
218+
await act(async () => render(<SwaggerUI selectedService={service1} selectedVersion="0" />, container));
219+
expect(container).not.toBeNull();
220+
});
130221
});

api-catalog-ui/frontend/src/utils/generateSnippets.js

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const wrapSelectors = {
2828
},
2929
};
3030

31-
export function getSnippetContent(req, target) {
31+
export function getSnippetContent(req, target, codeSnippet) {
3232
// get extended info about request
3333
const { spec, oasPathMethod } = req.toJS();
3434
const { path, method } = oasPathMethod;
@@ -37,7 +37,20 @@ export function getSnippetContent(req, target) {
3737
let snippet;
3838
try {
3939
// set request snippet content
40-
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0].content;
40+
if (
41+
codeSnippet !== null &&
42+
codeSnippet !== undefined &&
43+
codeSnippet.codeBlock !== undefined &&
44+
codeSnippet.codeBlock !== null
45+
) {
46+
if (codeSnippet.endpoint === path) {
47+
snippet = codeSnippet.codeBlock;
48+
} else {
49+
snippet = null;
50+
}
51+
} else {
52+
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0].content;
53+
}
4154
} catch (err) {
4255
snippet = JSON.stringify(snippet);
4356
}
@@ -50,47 +63,64 @@ export function getSnippetContent(req, target) {
5063
* @param title the code snippet title
5164
* @param syntax the syntax used for indentation
5265
* @param target the language target
53-
* @returns snippet code snippet content or an error in case of failure
66+
* @returns codeSnippet the code snippet
5467
*/
55-
export function generateSnippet(system, title, syntax, target) {
68+
export function generateSnippet(system, title, syntax, target, codeSnippet) {
5669
return system.Im.fromJS({
5770
title,
5871
syntax,
59-
fn: (req) => getSnippetContent(req, target),
72+
fn: (req) => getSnippetContent(req, target, codeSnippet),
6073
});
6174
}
6275

6376
/**
64-
* Custom Plugin which extends the SwaggerUI to generate simple snippets
77+
* Custom Plugin which extends the SwaggerUI to generate customized snippets
6578
*/
66-
// eslint-disable-next-line import/prefer-default-export
67-
export const BasicSnippedGenerator = {
68-
statePlugins: {
69-
// extend some internals to gain information about current path, method and spec in the generator function
70-
spec: wrapSelectors.spec,
71-
// extend the request snippets core plugin
72-
requestSnippets: {
73-
wrapSelectors: {
74-
// add additional snippet generators here
75-
getSnippetGenerators:
76-
(ori, system) =>
77-
(state, ...args) =>
78-
ori(state, ...args)
79-
.set('java_unirest', generateSnippet(system, 'Java Unirest', 'java', 'java_unirest'))
80-
.set(
81-
'javascript_jquery',
82-
generateSnippet(system, 'jQuery AJAX', 'javascript', 'javascript_jquery')
83-
)
84-
.set(
85-
'javascript_xhr',
86-
generateSnippet(system, 'Javascript XHR', 'javascript', 'javascript_xhr')
87-
)
88-
.set('python', generateSnippet(system, 'Python', 'python', 'python'))
89-
.set('c_libcurl', generateSnippet(system, 'C (libcurl)', 'bash', 'c_libcurl'))
90-
.set('csharp_restsharp', generateSnippet(system, 'C#', 'c#', 'csharp_restsharp'))
91-
.set('go_native', generateSnippet(system, 'Go', 'bash', 'go_native'))
92-
.set('node_fetch', generateSnippet(system, 'NodeJS', 'javascript', 'node_fetch')),
79+
export function CustomizedSnippedGenerator(codeSnippets) {
80+
return {
81+
statePlugins: {
82+
// extend some internals to gain information about current path, method and spec in the generator function
83+
spec: wrapSelectors.spec,
84+
// extend the request snippets core plugin
85+
requestSnippets: {
86+
wrapSelectors: {
87+
getSnippetGenerators:
88+
(ori, system) =>
89+
(state, ...args) => {
90+
let useSet = ori(state, ...args);
91+
// eslint-disable-next-line no-restricted-syntax
92+
for (const codeSnippet of codeSnippets) {
93+
const newSnippet = generateSnippet(
94+
system,
95+
`Customized Snippet - ${codeSnippet.language}`,
96+
codeSnippet.language,
97+
'target',
98+
codeSnippet
99+
);
100+
useSet = useSet.set(codeSnippet.endpoint + codeSnippet.language, newSnippet);
101+
}
102+
useSet = useSet
103+
.set(
104+
'java_unirest',
105+
generateSnippet(system, 'Java Unirest', 'java', 'java_unirest', null)
106+
)
107+
.set(
108+
'javascript_jquery',
109+
generateSnippet(system, 'jQuery AJAX', 'javascript', 'javascript_jquery', null)
110+
)
111+
.set(
112+
'javascript_xhr',
113+
generateSnippet(system, 'Javascript XHR', 'javascript', 'javascript_xhr', null)
114+
)
115+
.set('python', generateSnippet(system, 'Python', 'python', 'python', null))
116+
.set('c_libcurl', generateSnippet(system, 'C (libcurl)', 'bash', 'c_libcurl', null))
117+
.set('csharp_restsharp', generateSnippet(system, 'C#', 'c#', 'csharp_restsharp', null))
118+
.set('go_native', generateSnippet(system, 'Go', 'bash', 'go_native', null))
119+
.set('node_fetch', generateSnippet(system, 'NodeJS', 'javascript', 'node_fetch', null));
120+
return useSet;
121+
},
122+
},
93123
},
94124
},
95-
},
96-
};
125+
};
126+
}

0 commit comments

Comments
 (0)