I am new to swagger. Currently, I am using swagger ui version v2.1.4. My API consists query parameters. Into that one parameter accepts JSON body. I want to show this parameter into textarea. Currently, it showing in the input tag . also, I want to display Parameter content type below that textarea. How I do that please help me?
In the current swagger 2.0 specification, you can not use complex values as query parameters. They can be primitives or arrays of primitive values. You can find out more from the specification directly:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameter-object
As this has been a commonly requested feature, it will be supported in the next version of the specification, but the feature will not be backported to the swagger 2.0 tooling.
add format in describing parameters
eg:
parameters:
- name: key
type: string
in: query
format: textarea
add custom plugin when init swagger-ui
// Custom plugin that adds extra stuff
const TextAreaPlugin = function() {
return {
wrapComponents: {
// add text above InfoContainer - same effect as above title
JsonSchema_string: (Original, runtime) => (props) => {
var React = runtime.React,
schema = props.schema || {},
errors = props.errors || {},
format = schema.format || "",
isDisabled = props.disabled;
errors = errors.toJS ? errors.toJS() : []
function handleOnChange(e) {
const inputValue = e.target.value;
props.onChange(inputValue)
}
if (format == "textarea") {
return React.createElement("div", null,
React.createElement("textarea", {
title: errors.length ? errors : "",
className: errors.length ? "invalid" : "",
value: props.value,
disabled: isDisabled,
onChange: handleOnChange
})
)
}
return React.createElement(Original, props);
},
}
}
};
// Begin Swagger UI call region
var ui = SwaggerUIBundle({
url: "./swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
TextAreaPlugin,
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
Objects as query parameters are now supported in OpenAPI 3.0. See this Q&A for an example:
Use object type query param in Swagger documentation
Related
At node.js, I just started working with swagger, and I want to integrate the parameter-validation schemas I created using 'joi' - with swagger.
There's https://www.npmjs.com/package/joi-to-swagger but I don't understand how to use the generated object in swagger...
This is how I use swagger:
swaggerAutogen(outputFile, endpointsFiles, doc);
This is how I use joi-to-swagger:
const { swagger, components } = j2s(postVersionInfoValidator);
How do I integrate the swagger-output.json created in the first step, with the swagger object created in the 2nd step?
Thanks
You can do something like this
Generate the Swagger schema using joi-to-swagger
import j2s from 'joi-to-swagger';
const { swagger: swaggerA } = j2s(joiSchemaA);
const { swagger: swaggerB } = j2s(joiSchemaB);
const { swagger: swaggerC } = j2s(joiSchemaC);
Add the generated schemas into the swagger-autogen options. Note the usage of #definitions instead of definition. This is to allow us to use the Swagger schema object generated from joi-to-swagger as is.
import swaggerAutogen from 'swagger-autogen';
const outputFile = './swagger-output.json';
const apiFiles = ['./app.js'];
const doc = {
info: {
title: 'Your API',
...
},
'#definitions': {
PayloadA: swaggerA,
PayloadB: swaggerB,
PayloadC: swaggerC,
},
...
};
swaggerAutogen({ openapi: '3.0.0' })(outputFile, apiFiles, doc);
Add the Swagger comments into your endpoints
app.post('/endpoint-a', (res, req) => {
// #swagger.summary = 'Perform stuff'
/* #swagger.requestBody = {
required: true,
schema: { $ref: "#/definitions/PayloadA" },
}
*/
res.send('A');
});
I'm modifying the code from this workshop to do cross-account rather than cross-region.
https://cdk-advanced.workshop.aws/start.html
The first thing I did was install and configure cdk-assume-role-credential-plugin and bootstrapped.
In the workshop they use a AwsCustomResource to get around the cross-region limitation of StringParameter.valueFromLookup.
static valueFromLookup(scope, parameterName) Requires that the stack this scope is defined in will have explicit account/region information. Otherwise, it will fail during synthesis.Using an AwsCustomResource allows them to override the region from stack.
const targetKeyLookupCR = new cr.AwsCustomResource(this, 'TargetKeyLookup', {
onUpdate: { // will also be called for a CREATE event
service: 'SSM',
action: 'getParameter',
parameters: {
Name: props.targetKeyIdSsmParameterName
},
region: props.targetRegion,
physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString())
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({resources: [parameterArn]})
});
Unfortunately you cannot override account of stack in a similar fashion. Adding an assumedRole does not help either. It always looks for parameter in stack's account.
I tried to use SecretsManager & AwsCustomResource to get around that cross-account limitation:
const targetKeyLookupCR = new cr.AwsCustomResource(this, 'TargetKeyLookup', {
onUpdate: {
service: 'SecretsManager',
action: 'getSecretValue',
parameters: {
SecretId: props.targetKeyIdSsmParameterName
},
assumedRoleArn: 'arn:aws:iam::111111111111:role/MultiRegionS3CrrKmsCmkXacct',
region: props.targetRegion,
physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString())
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({resources: [parameterArn]})
});
const secretString = targetKeyLookupCR.getResponseField(dataPath);
The code above returns a string that looks like this.
"{"password":"/];asdf(5;{ASDF=L%UuVxasDFHg`(:l","MyKeyID":"arn:aws:kms:us-west-1: 111111111111:key/1111a22b-3c44-5ddd-66e7-f8f9999a1111"}"
I can see it in CloudWatch:
2021-08-14T04:34:15.641Z c5ae47f7-1e4a-43a3-a475-d0d16ea7e1be INFO Responding {"Status":"SUCCESS","Reason":"OK",...
"SecretString":"{"password":"/];asdf(5;{ASDF=L%UuVxasDFHg`(:l","MyKeyID":"arn:aws:kms:us-west-1: 111111111111:key/1111a22b-3c44-5ddd-66e7-f8f9999a1111}"...}
In the workshop they use the response directly:
role.addToPolicy(new iam.PolicyStatement({
resources: [targetKeyLookupCR.getResponseField('Parameter.Value')],
actions: ['kms:Encrypt'] }));
To get the Value of MyKeyID, I've tried...
JSON.parse and splitting the string. No matter what I try ends up with an error like 'Unexpected token $ in JSON at position 0' or 'TypeError: Cannot read property 'split' of undefined'
This led me to https://docs.aws.amazon.com/cdk/latest/guide/tokens.html#tokens_json, which I definitely thought was going to be the answer! It was not. More 'Unexpected token $ in JSON at position 0' errors.
const stack = cdk.Stack.of(this);
const secretString = targetKeyLookupCR.getResponseField('SecretString');
const jsonString = stack.toJsonString(secretString);
const jsonObj = JSON.parse(jsonString);
Update:
From this https://docs.aws.amazon.com/cdk/api/latest/docs/core-readme.html#cfnjson I got a different error that indicates it has the right string, but just can't parse it properly. Unexpected token p in JSON at position 3 at JSON.parse ().
const secretString = targetKeyLookupCR.getResponseField('SecretString');
const cfnJson = new CfnJson(this, 'cfn-json', {
value: secretString,
});
// #ts-ignore
const myKeyId = cfnJson.MyKeyID || '*';
This is because CfnJson adds quotes around string:
"Value": {
"Fn::Join": [
"",
[
"\"",
{
"Fn::GetAtt": [
"MySourceTargetKeyLookupACF65EAE",
"SecretString"
]
},
"\""
]
]
}
I'm not sure how to proceed. How would I get the ARN from secretString as plain text?
I guess I was looking for a more elegant solution, but this works...
const secretString = targetKeyLookupCR.getResponseField('SecretString');
const myKeyId = cdk.Fn.select(7,cdk.Fn.split('"', secretString));
It splits the secretString into an array using double quote as delimiter
cdk.Fn.split('"', secretString)
and selects the 7th item from array produced by split
cdk.Fn.select(7, <array>)
I have configured Swagger within my Feather.js app and it automatically generates docs for all endpoints on each service. Now, some endpoints on some service I want to omit from being generated as docs, because I simply disallow these endpoints or have some hidden logic behind them, that does not allow external calls.
F.e. I have the following setup for the endpoints of my /users/me service:
before: {
all: [authenticate('jwt')],
find: [
/*
* We don't use an ID when calling `/users/me` like `/users/me/<id>`, and therefore Feathers understands the
* incoming request as a `find` method instead of `get`, therefore we simply redirect it internally.
*/
async context => {
context.result = await context.service.get(context.params.user.id); // eslint-disable-line
return context;
}
],
get: [
iff(isProvider('external'), disallow()),
includeGender()
],
create: [disallow()],
update: [setAuthenticatedUserId()],
patch: [setAuthenticatedUserId()],
remove: [setAuthenticatedUserId()]
}
As you can see from the logic setup, I want to have the following docs generated:
I've followed these docs regarding feathers-swagger. I use the schemasGenerator(service, model, modelName, schemas) to generate docs for each service. Understandably this will generate the same schema of docs for each service. I tried adding custom stuff, as per the github module explanations, by either adding the docs object:
service.docs = {
...service.docs,
operations: {
find: false,
create: false
}
};
or adding a global operations: { find: false, create: false } object on the Swagger config.
The first option doesn't have an effect, and the second option applies it to all endpoints, which doesn't help me.
You must use the 'ignore' option to exclude the end-points that you want to. You may either specify the 'tags' array or the 'paths' array.
app.configure(swagger({
docsPath: '/api/docs',
uiIndex: true,
specs: {
info: {
title: 'API Docs',
description: 'Rest APIs',
version: '1.0.0',
},
schemes: ['http', 'https'],
},
ignore: {
paths: [
'users'
]
}
}));
You can also ignore end-points from service level.
usersService.docs = {
description: 'A service to manage users',
definitions: {
users: m2s(options.Model),
'users_list': {
type: 'array',
items: { $ref: '#/definitions/users' }
}
},
securities: ['find', 'get', 'update', 'patch', 'remove'],
operations: {'create': false}
};
Get complete documentation for feathers-swagger here
I'm trying to get a combined record set from User Stories and Defects. I have filters for each that work (e.g. Defect State != Closed and User Story Direct Child Count = 0) but I'm unable to have a combined query or custom query that will work. For example, the following code brings back User Stories but inherently filters out all defects.
I'm sure there are multiple ways of doing this but how do you get a combined result set of multiple types with filters specific for each type? Thanks.
_getData: function(name) {
var deferred = Ext.create('Deft.Deferred');
Ext.create('Rally.data.wsapi.artifact.Store', {
models: ['UserStory', 'Defect'],
pageSize: 2000,
fetch: ['c_MyCustomField', 'ScheduleState', 'PlanEstimate', 'Name'],
filters: [
{ property: 'ScheduleState', operator: '!=', value: 'Accepted' },
function(item){
var dirChildCountIsGood = false;
try
{
if (item.DirectChildrenCount > 0)
dirChildCountIsGood = false;
}
catch(ex) {}
return false;
},
/* or */{ property: 'DirectChildrenCount', operator: '=', value: '0' }
//{ property: 'State', operator: '!=', value: 'Closed' }
],
sorters: [
{ property: 'c_MyCustomField', direction: 'ASC'} // Same field for both User Stories and Defects
],
autoLoad: true,
listeners: {
scope: this,
load: this._onRecordsLoaded
}
});
console.log('Call to WSAPI store complete.');
return deferred;
}
This is an unfortunate weirdness with the artifact endpoint. You can work around it by using a special hidden TypeDefOid attribute in your query to get the various clauses to only apply to the correct types. Longer term we hope to make enhance the WSAPI query language to better support this type of scenario.
Build two filters like so:
var nonClosedDefectsFilter = Rally.data.wsapi.Filter.and([
{
property: 'TypeDefOid',
value: 12345 //replace with your defect typedef oid
},
{
property: 'State',
operator: '!='
value: 'Closed'
}
]);
var leafStoryFilter = Rally.data.wsapi.Filter.and([
{
property: 'TypeDefOid',
value: 23456 //replace with your story typedef oid
},
{
property: 'DirectChildrenCount',
value: 0
}
]);
And then or them together when you pass them to your store at creation time:
Ext.create('Rally.data.wsapi.artifact.Store', {
//other config from above omitted for brevity
filters: [nonClosedDefectsFilter.or(leafStoryFilter)]
});
I have an ASP.NET MVC application which is executing a search against a products database. I want to display the results in a jqGrid using the TreeGrid module. I don't really need the grid to be AJAX-y because the data is static and it is small enough that it can all be sent to the client at once.
First question: how do I set up jqGrid so that instead of pulling the JSON data from a URL it just looks in a JS variable or something?
Secondly, what is the most appropriate way to get ASP.NET MVC to put JSON data into a JavaScript variable? I already have the List in my controller and just want to somehow get it out into a JS variable after JSON-ing it.
Or am I fighting against the current too much and just accept the AJAX-y way that jqGrid seems to want to work?
Thanks,
~ Justin
Here is how to display a jqGrid tree using a JavaScript function.
$(document).ready(function() {
TreeDemo.setupGrid($("#tree"));
});
TreeDemo = {
data: { A: ["A1", "A2"], B: ["B1", "B2"] },
setupGrid: function(grid) {
grid.jqGrid({
colNames: ['Name'],
colModel: [
{ name: 'Name', index: 'Name', width: "250em" }
],
datatype: TreeDemo.treeData,
loadui: "none",
sortname: 'Number',
treeGrid: true,
treeGridModel: "adjacency",
sortorder: "asc"
})
},
treeData: function(postdata) {
var items = postdata.nodeid ? TreeDemo.data[postdata.nodeid] : TreeDemo.data;
var i = 0;
var rows = new Array();
for (val in items) {
var isLeaf = postdata.nodeid != undefined;
rows[i] = {
Name: val,
Id: val,
level: postdata.nodeid ? 1 : 0,
parent: postdata.nodeid || null,
isLeaf: isLeaf ? "true" : "false",
expanded: "false"
}
i++;
}
$("#tree")[0].addJSONData({
Total: 1,
Page: 1,
Records: 2,
Rows: rows
});
}
};
Note that there are lots of options for how you do this and my example is only one.
The way I would get the JSON into a JS var is to either:
Write a HTML Helper which emits a short script to the page.
Write an action which returns a JavaScriptResult to get the data in a file, if, for some reason, you can't have the data inline.
You create the JSON using the .NET JavaScript serializer. Look at the JsonResult.ExecuteResult in the MVC source code for an example.
See the Data Manipulation page in the jqGrid documentation wiki. There you'll find many ways to feed the data to the grid.
There is also a Table_to_jqGrid plugin that may be an useful option.