Skip to content

Commit

Permalink
API console and api-key
Browse files Browse the repository at this point in the history
  • Loading branch information
mrin9 committed Feb 4, 2019
1 parent c435825 commit 93b22ab
Show file tree
Hide file tree
Showing 22 changed files with 808 additions and 411 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<img alt="MrinDoc logo" src="https://github.com/mrin9/RapiDoc/blob/master/logo.png" width="60px" />

<img src="https://badgen.net/badge/license/MIT/blue">
[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/rapidoc)



# RapiDoc
Custom Eelement for Open-API spec viewing

Expand All @@ -17,8 +22,9 @@ Custom Eelement for Open-API spec viewing


## Roadmap
- Get the bundle size even smaller (~ 115 Kb gzipped)
- Allow replacing logo
- &#128077; Get the bundle size even smaller (~ 125 Kb gzipped)
- &#128077; Provide a console to try out the APIs
- &#128077; HTTP and Token based Authentication process
- Enable OAuth
- Search API Functionality
- Provide a console to try out the APIs
- Enable OAuth, HTTP and Token based Authentication process
- Allow replacing logo
4 changes: 3 additions & 1 deletion dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@
>
</rapi-doc>
-->
<rapi-doc spec-url="https://petstore.swagger.io/v2/swagger.json" ></rapi-doc>
<rapi-doc spec-url="https://petstore.swagger.io/v2/swagger.json"
theme="light"
></rapi-doc>
<script type="text/javascript" src="rapidoc-min.js"></script></body>

</html>
Binary file added dist/index.html.gz
Binary file not shown.
331 changes: 205 additions & 126 deletions dist/rapidoc-min.js

Large diffs are not rendered by default.

Binary file added dist/rapidoc-min.js.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion dist/rapidoc-min.js.map

Large diffs are not rendered by default.

Binary file added dist/rapidoc-min.js.map.gz
Binary file not shown.
65 changes: 65 additions & 0 deletions dist/report.html

Large diffs are not rendered by default.

331 changes: 205 additions & 126 deletions docs/rapidoc-min.js

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@
>
</rapi-doc>
-->
<rapi-doc spec-url="https://petstore.swagger.io/v2/swagger.json" ></rapi-doc>
<rapi-doc spec-url="https://petstore.swagger.io/v2/swagger.json"
theme="light"
></rapi-doc>
</body>

</html>
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rapidoc",
"version": "1.0.4",
"version": "2.0.0",
"description": "RapiDoc - Open API spec viewer with built in console",
"author": "Mrinmoy Majumdar <[email protected]>",
"repository": {
Expand Down Expand Up @@ -35,6 +35,7 @@
},
"devDependencies": {
"clean-webpack-plugin": "^1.0.1",
"compression-webpack-plugin": "^2.0.0",
"css-loader": "^2.1.0",
"file-loader": "^3.0.1",
"filemanager-webpack-plugin": "^2.0.5",
Expand Down
52 changes: 37 additions & 15 deletions src/components/api-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,19 @@ export default class ApiRequest extends LitElement {

static get properties() {
return {
server :{type: String},
method :{type: String},
path :{type: String},
parameters :{type: Array},
request_body:{type: Object},
responseMessage:{type: String, attribute:false},
responseText : {type: String, attribute:false},
responseHeaders: {type: String, attribute:false},
responseStatus : {type: String, attribute:false},
responseUrl : {type: String, attribute:false},
server : { type: String },
apiKeyName : { type: String, attribute: 'api-key-name' },
apiKeyValue : { type: String, attribute: 'api-key-value' },
apiKeyLocation: { type: String, attribute: 'api-key-location' },
method : { type: String },
path : { type: String },
parameters : { type: Array },
request_body : { type: Object },
responseMessage: { type: String, attribute:false },
responseText : { type: String, attribute:false },
responseHeaders: { type: String, attribute:false },
responseStatus : { type: String, attribute:false },
responseUrl : { type: String, attribute:false },
};
}

Expand All @@ -150,7 +153,7 @@ export default class ApiRequest extends LitElement {
<div class="param-type">${unsafeHTML(getTypeInfo(param.schema))}</div>
</td>
<td style="min-width:100px">
<input type="text" class="request-param" data-pname="${param.name}" data-ptype="${paramType}" style="width:100%" value="${param.example?param["x-example"]:''}">
<input type="text" class="request-param" data-pname="${param.name}" data-ptype="${paramType}" style="width:100%" value="${param.example?param.example:''}">
</td>
<td>
${param.description?html`<span class="m-markdown"> ${unsafeHTML(marked(param.description))} </span> `:``}
Expand Down Expand Up @@ -275,10 +278,20 @@ export default class ApiRequest extends LitElement {

apiCallTemplate(){
return html`
<div style="display:flex; align-items: center; margin:16px 0">
<div style="font-size:12px; margin:0 5px; width:calc(100% - 50px);">
<span style="font-weight:bold;">API Server:</span>
<span class='link'> ${this.server?this.server:location.origin}</span>
<div style="display:flex; align-items: center; margin:16px 0; font-size:12px;">
<div style="display:flex; flex-direction:column; margin:0 5px; width:calc(100% - 50px);">
<div style="display:flex;flex-direction:row;overflow:hidden;"> <div style="font-weight:bold;">API_Server: </div>
${this.server?html`${this.server}`
: html`<div style="font-weight:bold;color:var(--error-color)">Not Set</div>`}
</div>
<div style="display:flex;flex-direction:row;overflow:hidden;line-height:16px;color:var(--fg2)">
${this.apiKeyValue && this.apiKeyName ? html`
<div style="font-weight:bold;color:var(--success-color)">Authentication: &nbsp; </div>
send <div style="font-family:var(--font-mono); color:var(--fg)"> '${this.apiKeyName}' </div>
in<div style="font-family:var(--font-mono); color:var(--fg)"> '${this.apiKeyLocation}' </div>
with value<div style="font-family:var(--font-mono); color:var(--fg)"> '${this.apiKeyValue.substring(0,3)+"***" }' </div>`
:html`<div style="font-weight:bold;color:var(--error-color)">No Authentication</div>`}
</div>
</div>
<button class="m-btn" @click="${this.onTryClick}">TRY</button>
</div>
Expand Down Expand Up @@ -359,6 +372,11 @@ export default class ApiRequest extends LitElement {
})
url = `${url}?${queryParam.toString()}`;
}

// Add authentication Query if provided
if (this.apiKeyValue && this.apiKeyName && this.apiKeyLocation==='query'){
url = `${url}&${this.apiKeyName}=${this.apiKeyValue}`;
}
url = `${this.server.replace(/\/$/, "")}${url}`;

//Header Params
Expand All @@ -367,6 +385,10 @@ export default class ApiRequest extends LitElement {
fetchOptions.headers[el.dataset.pname] = el.value;
}
});
// Add Authentication Header if provided
if (this.apiKeyValue && this.apiKeyName && this.apiKeyLocation==='header'){
fetchOptions.headers[this.apiKeyName] = this.apiKeyValue;
}

//Form Params
if (formParamEls.length>=1){
Expand Down
20 changes: 15 additions & 5 deletions src/components/end-point.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ export default class EndPoint extends LitElement {
return html`
${FontStyles}
<style>
.m-endpoint.expanded{
margin-bottom:16px;
}
.m-endpoint.expanded{margin-bottom:16px; }
.m-endpoint > .head{
border-width:1px 1px 1px 5px;
border-style:solid;
Expand Down Expand Up @@ -174,7 +172,16 @@ export default class EndPoint extends LitElement {
</div>`
:``}
<div class='req-resp-container'>
<api-request class="request" server="${this.server}" method="${this.path.method}", path="${this.path.path}" .parameters="${this.path.parameters}" .request_body="${this.path.requestBody}" ></api-request>
<api-request class="request"
server="${this.server}"
method="${this.path.method}",
path="${this.path.path}"
api-key-name="${this.apiKeyName}"
api-key-value="${this.apiKeyValue}"
api-key-location="${this.apiKeyLocation}"
.parameters="${this.path.parameters}"
.request_body="${this.path.requestBody}"
></api-request>
<api-response class="response" .responses="${this.path.responses}"></api-response>
</div>
</div>`
Expand All @@ -185,7 +192,10 @@ export default class EndPoint extends LitElement {

static get properties() {
return {
server: {type:String},
server : {type:String},
apiKeyName : { type: String, attribute: 'api-key-name' },
apiKeyValue : { type: String, attribute: 'api-key-value' },
apiKeyLocation: { type: String, attribute: 'api-key-location' },
layout: {type:String},
path : {type:Object}
};
Expand Down
14 changes: 12 additions & 2 deletions src/components/end-points.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,23 @@ export default class EndPoints extends LitElement {
render() {
return html`
${this.paths.map(
path => html`<end-point server="${this.server}" layout="${this.layout}" .path=${path}> </end-point>`
path => html`<end-point
server="${this.server}"
api-key-name="${this.apiKeyName}"
api-key-value="${this.apiKeyValue}"
api-key-location="${this.apiKeyLocation}"
layout="${this.layout}"
.path=${path}
> </end-point>`
)}`
}

static get properties() {
return {
server: {type: String},
server : { type: String },
apiKeyName : { type: String, attribute: 'api-key-name' },
apiKeyValue : { type: String, attribute: 'api-key-value' },
apiKeyLocation: { type: String, attribute: 'api-key-location' },
layout: {type: String},
paths : {type: Object}
};
Expand Down
145 changes: 139 additions & 6 deletions src/components/security-schemes.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,155 @@
import { LitElement, html } from 'lit-element';
import {unsafeHTML} from 'lit-html/directives/unsafe-html.js';
import marked from 'marked';

import FontStyles from '@/styles/font-styles';
import TableStyles from '@/styles/table-styles';
import InputStyles from '@/styles/input-styles';

// Create your custom component
export default class SecuritySchemes extends LitElement {
render() {
return html`
${FontStyles}
<div class="sub-title regular-font">AUTHENTICATION</div>
<div style="font-size:12px; font-weight:bold; color:var(--error-color)">This section is under construction </div>
`
${TableStyles}
${InputStyles}
<div>AUTHENTICATION</div>
<table style="width:auto" class="m-table">
<tr>
<th >Type </th>
<th> Authentication Procedure </th>
</tr>
${Object.keys(this.schemes).map(s => html`
<tr>
<td>
<div style="font-weight:bold">${this.schemes[s].type}: ${this.schemes[s].scheme}</div>
${this.schemes[s].description?html`
<div class="m-markdown">
${unsafeHTML(marked(this.schemes[s].description))}
</div>`
:''}
</td>
<td>
${this.schemes[s].type==='apiKey'?html`
Send <code>'${this.schemes[s].name}'</code> in <code>'${this.schemes[s].in}'</code> with the given value
<div class="api-key" data-type="${this.schemes[s].type}" data-in="${this.schemes[s].in}" data-name="${this.schemes[s].name}" style="margin:5px 0">
<input type="text" name="token" style="width:402px;" placeholder="api-token" >
<button
class="m-btn"
data-action="${this.keyValue?'CLEAR':'SET'}"
@click="${this.dispatchChange}"
>${this.keyValue?'CLEAR':'SET'}</button>
</div>
`:``}
${this.schemes[s].type==='http' && this.schemes[s].scheme==='basic'?html`
Send <code>'Authorization'</code> in header which will contains the word <code>'Basic'</code> followed by a space and a base64-encoded string username:password.
<div class="api-key " data-type="${this.schemes[s].type}" data-scheme="${this.schemes[s].scheme}" data-in="header" data-name="Authorization" style="margin:15px 0">
<input type="text" name="username" style="width:200px;" placeholder="username">
<input type="text" name="password" style="width:200px;" placeholder="password">
<button
class="m-btn"
data-action="${this.keyValue?'CLEAR':'SET'}"
@click="${this.dispatchChange}"
>${this.keyValue?'CLEAR':'SET'}</button>
</div>
`:``}
${this.schemes[s].type==='http' && this.schemes[s].scheme==='bearer'?html`
Send <code>'Authorization'</code> in header which will contains the word <code>'Bearer'</code> ffollowed by a space and a Token String.
<div class="api-key" data-type="${this.schemes[s].type}" data-scheme="${this.schemes[s].scheme}" data-in="header" data-name="Authorization" style="margin:15px 0">
<input type="text" name="token" style="width:402px;" placeholder="api-token">
<button
class="m-btn"
data-action="${this.keyValue?'CLEAR':'SET'}"
@click="${this.dispatchChange}"
>${this.keyValue?'CLEAR':'SET'}</button>
</div>
`:``}
${this.schemes[s].type==='oauth2'?html`
<div style="width:500px">
${Object.keys(this.schemes[s].flows).map(f => html`
${this.schemes[s].flows[f].authorizationUrl?html`<div><b>Auth URL:</b> <code style="color:#999"> ${this.schemes[s].flows[f].authorizationUrl}</code></div>`:``}
${this.schemes[s].flows[f].tokenUrl?html`<div><b>Token URL:</b> <code style="color:#999"> ${this.schemes[s].flows[f].tokenUrl}</code></div>`:``}
${this.schemes[s].flows[f].refreshUrl?html`<div><b>Refresh URL:</b> <code style="color:#999"> ${this.schemes[s].flows[f].refreshUrl}</code></div>`:``}
<div class="oauth" style="margin:5px 0">
<input type="text" name="client" style="width:200px;" placeholder="client-id">
<input type="text" name="secret" style="width:200px;" placeholder="client-secret">
</div>
`)}
</div>
`:``}
</td>
</tr>`
)}
</table>`
}

static get properties() {
return {
server: {type: String},
layout: {type: String},
paths : {type: Object}
schemes: {type: Object},
keyValue:{type: String}
};

}

dispatchChange(e){
let apiEl = e.target.closest(".api-key");
if (!apiEl){
return;
}

let keyType = apiEl.dataset.type;
let keyLocation = apiEl.dataset.in;
let keyName = apiEl.dataset.name;

if (e.target.dataset.action === "CLEAR"){
this.keyValue = "";
let tokenEl = apiEl.querySelector("input[name=token]");
if (tokenEl){
tokenEl.value="";
}
}
else{
if (keyType==="apiKey"){
let tokenEl = apiEl.querySelector("input[name=token]");
if (tokenEl){
this.keyValue = tokenEl.value;
}

}
else if (keyType==="http"){
let securityScheme=apiEl.dataset.scheme;
if (securityScheme==="basic"){
let userNameEl = apiEl.querySelector("input[name=username]");
let passwordEl = apiEl.querySelector("input[name=password]");
if (userNameEl && passwordEl){
this.keyValue = 'Basic '+ btoa(userNameEl.value+":"+passwordEl.value);
}

}
else if (securityScheme==="bearer"){
let tokenEl = apiEl.querySelector("input[name=token]");
if (tokenEl){
this.keyValue = "Bearer " + tokenEl.value;
}
}
}
}


let event = new CustomEvent("change", {
detail: {
keyType:keyType,
keyName:keyName,
keyValue:this.keyValue,
keyLocation:keyLocation,
}
});
this.dispatchEvent(event);

}


}
// Register the element with the browser
customElements.define('security-schemes', SecuritySchemes);
Loading

0 comments on commit 93b22ab

Please sign in to comment.