Swagger View
MODIFY
angular.json
angular.json
"src/assets"
],
"styles": [
- "src/styles.scss",
- "./node_modules/angular2-toaster/src/toaster.scss"
+ "src/styles/styles.scss",
+ "./node_modules/angular2-toaster/src/toaster.scss",
+ "./node_modules/swagger-ui-dist/swagger-ui.css",
+ "src/styles/swagger-custom-styles.css"
],
"scripts": [
- "./node_modules/hammerjs/hammer.min.js"
+ "./node_modules/hammerjs/hammer.min.js",
+ "./node_modules/swagger-ui-dist/swagger-ui-bundle.js",
+ "./node_modules/swagger-ui-dist/swagger-ui-standalone-preset.js"
]
},
"configurations": {
"src/assets"
],
"styles": [
- "src/styles.scss",
- "./node_modules/angular2-toaster/src/toaster.scss"
+ "src/styles/styles.scss",
+ "./node_modules/angular2-toaster/src/toaster.scss",
+ "./node_modules/swagger-ui-dist/swagger-ui.css",
+ "src/styles/swagger-custom-styles.css"
],
"scripts": []
}

MODIFY
package.json
package.json
"keycloak-js": "^5.0.0",
"ngx-logger": "^4.0.7",
"rxjs": "^6.4.0",
+ "swagger-ui-dist": "^3.24.3",
"tslib": "^1.10.0",
"zone.js": "~0.9.1"
},

MODIFY
src/app/app-routing.module.ts
src/app/app-routing.module.ts
@@ -7,9 +7,15 @@ import {EditDeveloperComponent} from './components/admin/edit-developer/edit-dev
import {DevportalGuard} from './auth/devportal.guard';
import {AdminGuard} from './auth/admin.guard';
import {NotAuthorizedComponent} from './components/not-authorized/not-authorized.component';
+import {SwaggerComponent} from './components/swagger/swagger.component';
const routes: Routes = [
{path: '', component: DeveloperComponent, canActivate: [DevportalGuard]},
+ {
+ path: 'swagger/developer/:developerId/organizations/:orgId/apis/:apiId/versions/:version/apiKey/:apiKey',
+ component: SwaggerComponent,
+ canActivate: [DevportalGuard]
+ },
{
path: 'admin',
component: AdminComponent,

MODIFY
src/app/app.module.ts
src/app/app.module.ts
@@ -28,6 +28,7 @@ import {MatButtonModule, MatInputModule, MatOptionModule, MatAutocompleteModule,
import {EditDeveloperComponent} from './components/admin/edit-developer/edit-developer.component';
import {NotAuthorizedComponent} from './components/not-authorized/not-authorized.component';
import {ToasterModule} from 'angular2-toaster';
+import {SwaggerComponent} from './components/swagger/swagger.component';
@NgModule({
@@ -41,6 +42,7 @@ import {ToasterModule} from 'angular2-toaster';
CreateDeveloperComponent,
ClientMappingComponent,
EditDeveloperComponent,
+ SwaggerComponent,
NotAuthorizedComponent
],
imports: [

MODIFY
src/app/components/developer/api-list/api-list.component.html
src/app/components/developer/api-list/api-list.component.html
<th mat-header-cell *matHeaderCellDef>API Version</th>
<td mat-cell *matCellDef="let element"> {{element.version}} </td>
</ng-container>
- <ng-container matColumnDef="ispublic">
+ <ng-container matColumnDef="organization">
<th mat-header-cell *matHeaderCellDef>API Organization</th>
<td mat-cell *matCellDef="let element"> {{element.organizationName}} </td>
</ng-container>
<td mat-cell *matCellDef="let element"> {{element.endpoint}} </td>
</ng-container>
+ <ng-container matColumnDef="options">
+ <th mat-header-cell *matHeaderCellDef>Options</th>
+ <td mat-cell *matCellDef="let element"> <a [routerLink]="element.swaggerURL">Swagger</a> </td>
+ </ng-container>
+
<tr mat-header-row *matHeaderRowDef="columnHeaders"></tr>
<tr mat-row *matRowDef="let row; columns: columnHeaders;"></tr>
</table>

MODIFY
src/app/components/developer/api-list/api-list.component.ts
src/app/components/developer/api-list/api-list.component.ts
@@ -13,6 +13,7 @@ export interface ApiListElement {
version: string;
endpoint: string;
organizationName: string;
+ swaggerURL: string;
}
@Component({
@@ -23,7 +24,7 @@ export interface ApiListElement {
export class ApiListComponent implements OnChanges {
- columnHeaders: string[] = ['ispublic', 'name', 'version', 'endpoint'];
+ columnHeaders: string[] = ['organization', 'name', 'version', 'endpoint', 'options'];
apiData: Array<ApiListElement> = [];
@@ -98,7 +99,8 @@ export class ApiListComponent implements OnChanges {
name: contract.apiName,
version: contract.apiVersion,
endpoint: this.buildApiEndpoint(gateway.endpoint, contract.apiOrganizationId, contract.apiId, contract.apiVersion, clientVersion.apiKey),
- organizationName: contract.apiOrganizationId
+ organizationName: contract.apiOrganizationId,
+ swaggerURL: '/swagger/developer/' + this.developerId + '/organizations/' + contract.apiOrganizationId + '/apis/' + contract.apiId + '/versions/' + contract.apiVersion + '/apiKey/' + clientVersion.apiKey
};
}

ADD
src/app/components/swagger/swagger.component.html
+<div id="swagger-editor"></div>

ADD
src/app/components/swagger/swagger.component.scss
src/app/components/swagger/swagger.component.scss
ADD
src/app/components/swagger/swagger.component.spec.ts
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SwaggerComponent } from './swagger.component';
+
+describe('SwaggerComponent', () => {
+ let component: SwaggerComponent;
+ let fixture: ComponentFixture<SwaggerComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SwaggerComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SwaggerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});

ADD
src/app/components/swagger/swagger.component.ts
+import {Component, Inject, OnInit} from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+
+declare const SwaggerUIBundle: any;
+
+@Component({
+ selector: 'app-swagger',
+ templateUrl: './swagger.component.html',
+ styleUrls: ['./swagger.component.scss']
+})
+export class SwaggerComponent implements OnInit {
+
+ constructor(@Inject('APIMAN_UI_REST_URL') private apimanUiRestUrl: string, private route: ActivatedRoute) { }
+
+ ngOnInit() {
+ const developerId = this.route.snapshot.paramMap.get('developerId');
+ const organizationId = this.route.snapshot.paramMap.get('orgId');
+ const apiId = this.route.snapshot.paramMap.get('apiId');
+ const version = this.route.snapshot.paramMap.get('version');
+
+ const apiKey = this.route.snapshot.paramMap.get('apiKey');
+
+ const swaggerURL = this.apimanUiRestUrl + '/developers/' + developerId + '/organizations/' + organizationId + '/apis/' + apiId + '/versions/' + version + '/definition';
+
+ const swaggerUI = SwaggerUIBundle({
+ dom_id: '#swagger-editor',
+ layout: 'BaseLayout',
+ presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIBundle.SwaggerUIStandalonePreset
+ ],
+ url: swaggerURL,
+ docExpansion: 'none',
+ operationsSorter: 'alpha',
+ onComplete: () => {
+ // set api key in swagger view to make it look like authorized for calls
+ // this option is not enough to send OPTION requests to gateway protected apis
+ // sending this api key as header in option requests are blocked by the browser
+ swaggerUI.preauthorizeApiKey('X-API-Key', apiKey);
+ },
+ requestInterceptor: (request) => {
+ if (request.url === swaggerURL) {
+ // set bearer token for authentication to get swagger file
+ request.headers.Authorization = 'Bearer ' + sessionStorage.getItem('apiman_keycloak_token');
+ } else {
+ // set api key to authorize all api requests also for option requests
+ request.url += '?apiKey=' + apiKey;
+ }
+ return request;
+ }
+ });
+ }
+
+}

RENAME
src/styles.scss
src/styles/styles.scss
/* You can add global styles to this file, and also import other style files */
-@import '~@angular/material/prebuilt-themes/indigo-pink.css';
+@import '../../node_modules/@angular/material/prebuilt-themes/indigo-pink.css';
@import url("https://fonts.googleapis.com/icon?family=Material+Icons");
@import url("https://fonts.googleapis.com/css?family=Roboto&display=swap");

ADD
src/styles/swagger-custom-styles.css
+/* SwaggerUI Styles Start */
+/* This stylesheet is used for runtime and API Management */
+
+:root {
+ /*SwaggerUI Colors*/
+ --swagger-post-bg: rgba(107, 155, 68, 0.25);
+ --swagger-post-border: #6B9B44;
+
+ --swagger-put-bg: rgba(234, 160, 30, 0.25);
+ --swagger-put-border: #EAA01E;
+
+ --swagger-get-bg: rgba(41, 150, 204, 0.25);
+ --swagger-get-border: #2996CC;
+
+ --swagger-delete-bg: rgba(208, 50, 55, 0.25);
+ --swagger-delete-border: #D03237;
+
+ --swagger-patch-bg: rgba(106, 116, 127, 0.25);
+ --swagger-patch-border: #6A747F;
+
+ --swagger-options-bg: rgba(112, 48, 122, 0.25);
+ --swagger-options-border: #70307A;
+
+ --swagger-head-bg: rgba(5, 97, 141, 0.25);
+ --swagger-head-border: #05618D;
+
+ --scheer-btn: #2996cc;
+ --scheer-btn-hover: #06628e;
+
+ --scheer-btn-alert: #d03237;
+ --scheer-btn-alert-hover: #ac1e1c;
+}
+
+.swagger-ui .opblock {
+ border: 2px solid;
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.swagger-ui .scheme-container, .swagger-ui .global-server-container {
+ -webkit-box-shadow: 0px 2px 0px 0px rgba(187,182,185,1);
+ -moz-box-shadow: 0px 2px 0px 0px rgba(187,182,185,1);
+ box-shadow: 0px 2px 0px 0px rgba(187,182,185,1);
+}
+
+.swagger-ui .opblock.opblock-post {
+ border-color: #6B9B44;
+ border-color: var(--swagger-post-border);
+ background: rgba(107, 155, 68, 0.25);
+ background: var(--swagger-post-bg);
+}
+
+.swagger-ui .opblock.opblock-post .opblock-summary-method {
+ background: #6B9B44;
+ background: var(--swagger-post-border);
+}
+
+.swagger-ui .opblock.opblock-post .opblock-summary {
+ border-color: #6B9B44;
+ border-color: var(--swagger-post-border);
+}
+
+.swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span:after {
+ background: #6B9B44;
+ background: var(--swagger-post-border);
+}
+
+.swagger-ui .opblock.opblock-put {
+ border-color: #EAA01E;
+ border-color: var(--swagger-put-border);
+ background: rgba(234, 160, 30, 0.25);
+ background: var(--swagger-put-bg);
+}
+
+.swagger-ui .opblock.opblock-put .opblock-summary-method {
+ background: #EAA01E;
+ background: var(--swagger-put-border);
+}
+
+.swagger-ui .opblock.opblock-put .opblock-summary {
+ border-color: #EAA01E;
+ border-color: var(--swagger-put-border);
+}
+
+.swagger-ui .opblock.opblock-put .tab-header .tab-item.active h4 span:after {
+ background: #EAA01E;
+ background: var(--swagger-put-border);
+}
+
+.swagger-ui .opblock.opblock-delete {
+ border-color: #D03237;
+ border-color: var(--swagger-delete-border);
+ background: rgba(208, 50, 55, 0.25);
+ background: var(--swagger-delete-bg);
+}
+
+.swagger-ui .opblock.opblock-delete .opblock-summary-method {
+ background: #D03237;
+ background: var(--swagger-delete-border);
+}
+
+.swagger-ui .opblock.opblock-delete .opblock-summary {
+ border-color: #D03237;
+ border-color: var(--swagger-delete-border);
+}
+
+.swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span:after {
+ background: #D03237;
+ background: var(--swagger-delete-border)
+}
+
+.swagger-ui .opblock.opblock-get {
+ border-color: #2996CC;
+ border-color: var(--swagger-get-border);
+ background: rgba(41, 150, 204, 0.25);
+ background: var(--swagger-get-bg);
+}
+
+.swagger-ui .opblock.opblock-get .opblock-summary-method {
+ background: #2996CC;
+ background: var(--swagger-get-border);
+}
+
+.swagger-ui .opblock.opblock-get .opblock-summary {
+ border-color: #2996CC;
+ border-color: var(--swagger-get-border);
+}
+
+.swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span:after {
+ background: #2996CC;
+ background: var(--swagger-get-border);
+}
+
+.swagger-ui .opblock.opblock-patch {
+ border-color: #6A747F;
+ border-color: var(--swagger-patch-border);
+ background: rgba(106, 116, 127, 0.25);
+ background: var(--swagger-patch-bg);
+}
+
+.swagger-ui .opblock.opblock-patch .opblock-summary-method {
+ background: #6A747F;
+ background: var(--swagger-patch-border);
+}
+
+.swagger-ui .opblock.opblock-patch .opblock-summary {
+ border-color: #6A747F;
+ border-color: var(--swagger-patch-border);
+}
+
+.swagger-ui .opblock.opblock-patch .tab-header .tab-item.active h4 span:after {
+ background: #6A747F;
+ background: var(--swagger-patch-border);
+}
+
+.swagger-ui .opblock.opblock-head {
+ border-color: #05618D;
+ border-color: var(--swagger-head-border);
+ background: rgba(5, 97, 141, 0.25);
+ background: var(--swagger-head-bg);
+}
+
+.swagger-ui .opblock.opblock-head .opblock-summary-method {
+ background: #05618D;
+ background: var(--swagger-head-border);
+}
+
+.swagger-ui .opblock.opblock-head .opblock-summary {
+ border-color: #05618D;
+ border-color: var(--swagger-head-border);
+}
+
+.swagger-ui .opblock.opblock-head .tab-header .tab-item.active h4 span:after {
+ background: #05618D;
+ background: var(--swagger-head-border);
+}
+
+.swagger-ui .opblock.opblock-options {
+ border-color: #70307A;
+ border-color: var(--swagger-options-border);
+ background: rgba(112, 48, 122, 0.25);;
+ background: var(--swagger-options-bg);
+}
+
+.swagger-ui .opblock.opblock-options .opblock-summary-method {
+ background: #70307A;
+ background: var(--swagger-options-border);
+}
+
+.swagger-ui .opblock.opblock-options .opblock-summary {
+ border-color: #70307A;
+ border-color: var(--swagger-options-border);
+}
+
+.swagger-ui .opblock.opblock-options .tab-header .tab-item.active h4 span:after {
+ background: #70307A;
+ background: var(--swagger-options-border);
+}
+
+.swagger-ui section.models,
+.swagger-ui section.models .model-container,
+.swagger-ui .opblock-body pre,
+.swagger-ui select,
+.swagger-ui .response-col_description__inner div.markdown,
+.swagger-ui .response-col_description__inner div.renderedMarkdown,
+.swagger-ui .opblock .opblock-summary-method,
+.swagger-ui .btn
+{
+ border-radius: 0;
+}
+
+.swagger-ui a.nostyle, .swagger-ui a.nostyle:visited {
+ color: #4B525A;
+}
+
+.swagger-ui .response-content-type.controls-accept-header select {
+ border-color: black;
+}
+
+.swagger-ui .opblock-body pre {
+ font-weight: 100;
+}
+
+.swagger-ui .btn.authorize svg {
+ fill: #ffffff
+}
+
+.swagger-ui .btn, .swagger-ui .btn.authorize, .swagger-ui .btn.execute {
+ color: #ffffff;
+ border-color: #2996cc;
+ border-color: var(--scheer-btn);
+ background-color: #2996cc;
+ background-color: var(--scheer-btn);
+}
+
+.swagger-ui .btn.cancel {
+ color: #ffffff;
+ border-color: #d03237;
+ border-color: var(--scheer-btn-alert);
+ background-color: #d03237;
+ background-color: var(--scheer-btn-alert);
+}
+
+.swagger-ui .btn:hover, .swagger-ui .btn.authorize:hover, .swagger-ui .btn.execute:hover {
+ color: #ffffff;
+ border-color: #06628e;
+ border-color: var(--scheer-btn-hover);
+ background-color: #06628e;
+ background-color: var(--scheer-btn-hover);
+}
+
+.swagger-ui .btn.cancel:hover {
+ color: #ffffff;
+ border-color: #ac1e1c;
+ border-color: var(--scheer-btn-alert-hover);
+ background-color: #ac1e1c;
+ background-color: var(--scheer-btn-alert-hover);
+}
+
+/*SwaggerUI Styles End*/
\ No newline at end of file

GW-270: Swagger View