How to add x-code-samples for ReDoc with Swashbuckle.AspNetCore? - swashbuckle

What's the best way to add x-code-samples for ReDoc to swagger.json through Swashbuckle.AspNetCore.Annotations?
EDIT (March 30, 2019)
I hope this is a better explanation.
There is a way in Swashbuckle.AspNetCore to add content to the generated swagger.json.
What's documented
(Example from GitHub-Page):
[HttpPost]
[SwaggerOperation(
Summary = "Creates a new product",
Description = "Requires admin privileges",
OperationId = "CreateProduct",
Tags = new[] { "Purchase", "Products" }
)]
public IActionResult Create([FromBody]Product product)
About what I try to achieve
What I'd like to do is something like this:
[MyCustomSwaggerOperation(
x-code-samples = [
{
"lang": "CSharp",
"source": "console.log('Hello World');"
},
{
"lang": "php",
"source": ...
}
]
)]
public IActionResult Create([FromBody]Product product)

Here is an IDocumentFilter that injects "x-code-samples" to a parameter
public class InjectSamples : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
PathItem path = swaggerDoc.Paths.Where(x => x.Key.Contains("Values")).First().Value;
path.Post.Parameters.FirstOrDefault().Extensions.Add("x-code-samples", "123456");
}
}
Yes you could complicate all this with annotations, but "x-code-samples" is not supported out of the box by Swashbuckle, so you will have to create your own and them use it on the iDocFilter.
In the comments you kept pointing out that IDocumentFilters are added after the swagger document has been generated, Yes we want that!
And the generated swagger.json with that looks like this:
"post": {
"tags": [ "Values" ],
"operationId": "ApiValuesPost",
"consumes": [ "application/json" ],
"produces": [],
"parameters": [
{
"name": "value",
"in": "body",
"required": false,
"schema": { "type": "string" },
"x-code-samples": "123456"
}
],
"responses": {
"200": { "description": "Success" }
}
}

Related

How to add organization,mobileno,email from bulk user endpoint "https://localhost:9443/t/carbon.super/scim2/Bulk" in WSO2IS

I used "https://localhost:9443/t/carbon.super/scim2/Bulk" to upload bulk users to WSO2IS. How to add organization,email and mobileno to following data set.
Here is my data object.
{
"failOnErrors": 1,
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:BulkRequest"
],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "qwerty1",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"userName": "Alexwso26.com",
"password": "12345678",
"name": {
"givenName": "Alex26 ",
"familyName": "Silva26"
},
"emails": [
{
"type": "home",
"value": "Alex26#g.com",
"primary": true
}
]
}
}
]
}
It is working fine. But email didn't update.
From your user creation payload, it updates the user's home email. If you Navigate to the Management console -> Main menu -> Claims -> List -> "http://wso2.org/claims" -> Emails - Home Email-> Edit and tick Supported by Default, and view that created user's profile. You can see that the given value has been updated.
Change the email attribute like the following payload. Then you can update the Email attribute of the user. Also, the following payload contains the attribute format for mobile number and organization.
{
"failOnErrors": 1,
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:BulkRequest"
],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "qwerty1",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"userName": "Alexwso26.com",
"password": "12345678",
"name": {
"givenName": "Alex26 ",
"familyName": "Silva26"
},
"emails": [
{
"value": "Alex26#g.com",
"primary": true
}
],
"phoneNumbers": [
{
"value": "0771234567",
"type": "mobile"
}
],
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" : {
"organization": "abc"
}
}
}
]
}
Refer to the following documents when forming payload when creating or managing users/groups via SCIM endpoint.
https://anuradha-15.medium.com/how-to-add-scim-extended-attributes-in-wso2-identity-server-71621f62c5d3
https://www.rfc-editor.org/rfc/rfc7643

Data does not match any schemas from 'oneOf'

I am getting this error after upgrading my api from .netcore2.2 to 3.1 and trying to generate using autorest with the --v3 switch
WARNING: Schema violation: Data does not match any schemas from
'oneOf'
I have tried with and without SerializeAsV2
I see from the Autorest docs that this warning is because of an supported feature.
anyOf, oneOf are not currently supported
In services.AddSwaggerGen I have
c.ParameterFilter<SwaggerEnumParameterFilter>();
c.SchemaFilter<SwaggerEnumFilter>();
where
public void Apply(OpenApiParameter parameter, ParameterFilterContext context)
{
var type = context.ApiParameterDescription.Type;
if (type.IsEnum)
parameter.Extensions.Add("x-ms-enum", new OpenApiObject
{
["name"] = new OpenApiString(type.Name),
["modelAsString"] = new OpenApiBoolean(false)
});
}
public class SwaggerEnumFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (model == null)
throw new ArgumentNullException("model");
if (context == null)
throw new ArgumentNullException("context");
if (context.Type.IsEnum)
model.Extensions.Add(
"x-ms-enum",
new OpenApiObject
{
["name"] = new OpenApiString(context.Type.Name),
["modelAsString"] = new OpenApiBoolean(false)
}
);
}
}
[update]
After upgrading to Autorest 3.0.6244 the warnings have changed to errors and the error message ends with
post > parameters > 0)
If I don't use the v3 switch I get the error
FATAL: swagger-document/individual/schema-validator - FAILED
FATAL: Error: [OperationAbortedException] Error occurred. Exiting.
Process() cancelled due to exception : [OperationAbortedException] Error occurred. Exiting.
I can see in the swagger.json that the parameters property "name" is not generating correctly. Here it contains "body" whereas previously it contained "info"
"/api/FrameLookUp": {
"post": {
"tags": [
"Frame"
],
"operationId": "FrameLookup",
"consumes": [
"application/json-patch+json",
"application/json",
"text/json",
"application/*+json"
],
"produces": [
"application/json"
],
"parameters": [
{
"in": "header",
"name": "Authorization",
"description": "access token",
"required": true,
"type": "String"
},
{
"in": "body",
"name": "body",
"schema": {
"$ref": "#/definitions/FrameRequest"
}
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/FrameResponse"
}
}
}
}
},
The controller is
[Produces("application/json")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api")]
public class FrameController : MyController
{
[ProducesResponseType(typeof(FrameResponse), StatusCodes.Status200OK)]
[HttpPost("FrameLookUp")]
public IActionResult FrameLookup([FromBody] FrameRequest info)
{
IMyResponse MyFunc(IMyRequest x) => FrameData.FrameLookUp(info);
return InnerMethod(MyFunc, info);
}
}
Update
I have also tried using the SwaggerParameter from Swashbuckle.AspNetCore.Annotations
[Update]
I am thinking that maybe I just need to try the release for issue 1766
I tried cloning the swashbuckle.aspnetcore repo but ran into this issue
[Update]
I added c.GeneratePolymorphicSchemas(); to the AddSwaggerGen options but it has not helped.
[Update]
Here is the first error message
ERROR: Schema violation: Data does not match any schemas from 'oneOf'
- https://localhost:44348/api-docs/v1/swagger.json:1951:8 ($.paths["/api/synchronise-management/get-product-images-Ids"].post.parameters)
Investigating line 1951 in swagger.json
In the working swagger ( generated from dotnet2.2 project ) the json looks very similar however the parameter order is swapped
The other difference I can see is the generated name of the parameter
I see from this question the error occurs in the same place
[Update]
when I add the --debug switch to the autorest call I get
/configuration
DEBUG: pipeline-emitter - END
DEBUG: configuration-emitter - END
DEBUG: swagger-document-override/md-override-loader - END
DEBUG: swagger-document/loader - END
DEBUG: swagger-document/individual/transform - START
DEBUG: swagger-document/individual/transform - END
DEBUG: swagger-document/individual/schema-validator - START
ERROR: Schema violation: Data does not match any schemas from 'oneOf'
- https://localhost:44348/api/v1/swagger.json:1951:8 ($.paths["/api/synchronise-management/get-product-images-Ids"].
[Update]
Here is the cut down json
{
"swagger": "2.0",
"info": {
"title": "myapi API31",
"description": "ASP.NET Core Web API",
"version": "v1"
},
"host": "localhost:44348",
"basePath": "/v1",
"schemes": [
"https"
],
"paths": {
"/api/Test": {
"get": {
"tags": [
"Auth"
],
"operationId": "Test",
"responses": {
"200": {
"description": "Success"
}
}
}
},
"/api/RequestToken": {
"post": {
"tags": [
"Auth"
],
"operationId": "RequestToken",
"consumes": [
"application/json-patch+json",
"application/json",
"text/json",
"application/*+json"
],
"produces": [
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"schema": {
"$ref": "#/definitions/TokenRequest"
}
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/TokenResponse"
}
}
}
}
},
"/api/FrameLookUp": {
"post": {
"tags": [
"Frame"
],
"operationId": "FrameLookup",
"consumes": [
"application/json-patch+json",
"application/json",
"text/json",
"application/*+json"
],
"produces": [
"application/json"
],
"parameters": [
{
"in": "header",
"name": "Authorization",
"description": "access token",
"required": true,
"type": "String"
},
{
"in": "body",
"name": "body",
"schema": {
"$ref": "#/definitions/FrameRequest"
}
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/FrameResponse"
}
}
}
}
}
},
"definitions": {
"TokenRequest": {
"required": [
"password",
"username"
],
"type": "object",
"properties": {
"username": {
"type": "string"
},
"password": {
"type": "string"
}
}
},
"TokenResponse": {
"type": "object",
"properties": {
"tokenResult": {
"type": "string"
}
}
},
"FramePackTypeEnum": {
"enum": [
"NotApplicable",
"PipeRack",
"LwBVan",
"VanTray",
"Car",
"CarryBag"
],
"type": "string",
"x-ms-enum": {
"name": "FramePackTypeEnum",
"modelAsString": false
}
},
"FrameRequest": {
"type": "object",
"properties": {
"qCodeJobId": {
"format": "int32",
"type": "integer"
},
"quantity": {
"format": "int32",
"type": "integer"
},
"widthInMm": {
"format": "int32",
"type": "integer"
},
"heightInMm": {
"format": "int32",
"type": "integer"
},
"ePackingType": {
"$ref": "#/definitions/FramePackTypeEnum"
},
"userEmail": {
"type": "string"
}
}
},
"FrameCaseEnum": {
"enum": [
"Case0_NoBraces",
"Case1_1Vertical_0Horizontal",
"Case2_2Vertical_0Horizontal",
"Case3_NVertical_0Horizontal",
"Case4_0Vertical_1Horizontal",
"Case5_1Vertical_1Horizontal",
"Case6_2Vertical_1Horizontal",
"Case7_NVertical_1Horizontal",
"Case8_0Vertical_2Horizontal",
"Case9_1Vertical_2Horizontal",
"Case10_2Vertical_2Horizontal",
"Case11_NVertical_2Horizontal",
"Case12_0Vertical_NHorizontal",
"Case13_1Vertical_NHorizontal",
"Case14_2Vertical_NHorizontal",
"Case15_NVertical_NHorizontal"
],
"type": "string",
"x-ms-enum": {
"name": "FrameCaseEnum",
"modelAsString": false
}
},
"FrameResponse": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"caseNumber": {
"$ref": "#/definitions/FrameCaseEnum"
},
"memberPriceEachExGst": {
"format": "double",
"type": "number"
},
"retailPriceEachExGst": {
"format": "double",
"type": "number"
}
}
}
}
}
With the .netcore2.2 api the request generates as
"FrameRequest": {
"type": "object",
"properties": {
"qCodeJobId": {
"format": "int32",
"type": "integer"
},
"quantity": {
"format": "int32",
"type": "integer"
},
"widthInMm": {
"format": "int32",
"type": "integer"
},
"heightInMm": {
"format": "int32",
"type": "integer"
},
"ePackingType": {
"enum": [
"NotApplicable",
"PipeRack",
"LwBVan",
"VanTray",
"Car",
"CarryBag"
],
"type": "string",
"x-ms-enum": {
"name": "FramePackTypeEnum",
"modelAsString": false
}
},
"userEmail": {
"type": "string"
}
}
}
Here is the command line I am running
autorest --input-file=.\myswagger.json --output-folder=generated --csharp --namespace=DDD --debug
Some links which the author, Kirsten Greed, put in comments:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore#schema-filters
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/1766
https://stackoverflow.com/questions/63857310/could-not-find-a-part-of-the-path-d-dev-swashbuckle-aspnetcore-src-swashbuckle
From your swagger.json we can see the validation shows:
https://validator.swagger.io/validator/debug?url=https://raw.githubusercontent.com/heldersepu/hs-scripts/master/swagger/63783800_swagger.json
{
"schemaValidationMessages": [
{
"level": "error",
"domain": "validation",
"keyword": "oneOf",
"message": "instance failed to match exactly one schema (matched 0 out of 2)",
"schema": {
"loadingURI": "http://swagger.io/v2/schema.json#",
"pointer": "/definitions/parametersList/items"
},
"instance": {
"pointer": "/paths/~1api~1FrameLookUp/post/parameters/0"
}
}
]
}
that lead us to your code:
that type: "String" should be: type: "string" with all lower case the error goes away

Kentico Kontent runtime resolution

I am having issue with kentico kontent a bit. Basically when I call _deliveryClient.GetItemsAsync<object> I am getting null even though the json below is being brought back.
{
"item": {
"system": {
"id": "0b9e6cf0-a9aa-422b-9e14-1576adfb6324",
"name": "Home",
"codename": "home",
"language": "default",
"type": "home",
"sitemap_locations": [],
"last_modified": "2020-04-30T17:16:48.706142Z"
},
"elements": {
"header": {
"type": "text",
"name": "Header",
"value": "This is my name"
},
"description": {
"type": "text",
"name": "Description",
"value": ".net specialist"
},
"background": {
"type": "modular_content",
"name": "Background",
"value": [
"universe"
]
}
}
},
"modular_content": {
"universe": {
"system": {
"id": "a8898eef-0f4b-4646-af72-c0a1e41ab165",
"name": "Universe",
"codename": "universe",
"language": "default",
"type": "background",
"sitemap_locations": [],
"last_modified": "2020-04-30T17:19:02.9586245Z"
},
"elements": {
"user_vid_or_imag": {
"type": "multiple_choice",
"name": "User Vid or Imag",
"value": [
{
"name": "Video",
"codename": "video"
}
]
},
"background_item": {
"type": "asset",
"name": "Background Item",
"value": [
{
"name": "Time Lapse Video Of Night Sky.mp4",
"description": null,
"type": "video/mp4",
"size": 2076845,
"url": "https://preview-assets-us-01.kc-usercontent.com:443/..."
}
]
}
}
}
}
}
However, if I use the concretion I get the Model back as expected. This is an issue even for members of a class e.g. linked items. The problem is that we have lots of models so we have opted to use the ModelGenerator kentico provides. The thing is we cannot tell the the Generator not to generate some of the objects so it will overwrite everything even though we only want to update one model. So this means I cannot go into every model and change the to some concretion because that will be overwritten.
The documentation says that should always work so is this a bug? or am I making a mistake somewhere.
You should always use the model generator in combination with partial classes. To enable customization via partial classes use the --generatepartials true switch. This will output something like:
Article.Generated.cs (will be always regenerated)
public partial class Article
{
public const string Codename = "article";
public const string TitleCodename = "title";
public const string BodyCopyCodename = "body_copy";
public const string RelatedArticlesCodename = "related_articles";
public string Title { get; set; }
public IRichTextContent BodyCopy { get; set; }
public IEnumerable<object> RelatedArticles { get; set; }
}
Article.cs (will be generated when it doesn't already exist, it will never be overwritten by the generator)
public partial class Article
{
// Space for your customizations
public IEnumerable<Article> ArticlesTyped => RelatedArticles.Cast<Article>();
}
Feel free to suggest improvements for the code generator at https://github.com/Kentico/kontent-generators-net/issues/new/choose
The most probable reason why your code doesn't work at the moment is that you haven't registered the implementation of the ITypeProvider interface. You can do so by adding it to the DI container (IServiceCollection):
services
.AddSingleton<ITypeProvider, CustomTypeProvider>();
.AddDeliveryClient(Configuration);
or by passing it to the DeliveryClientBuilder
CustomTypeProvider customTypeProvider = new CustomTypeProvider();
IDeliveryClient client = DeliveryClientBuilder
.WithProjectId("975bf280-fd91-488c-994c-2f04416e5ee3")
.WithTypeProvider(customTypeProvider)
.Build();
as described in the docs. You can either generate the CustomTypeProvider by the model generator utility or implement it by hand. It should look similar to this:
public class CustomTypeProvider : ITypeProvider
{
private static readonly Dictionary<Type, string> _codenames = new Dictionary<Type, string>
{
// <CLI type, model codename in Kontent>
{typeof(Article), "article"}
};
public Type GetType(string contentType)
{
return _codenames.Keys.FirstOrDefault(type => GetCodename(type).Equals(contentType));
}
public string GetCodename(Type contentType)
{
return _codenames.TryGetValue(contentType, out var codename) ? codename : null;
}
}
Alternatively, you can specify the type when calling GetItemsAsync() in the following way: _deliveryClient.GetItemsAsync<Article>() but this will resolve only the 1st level type. Any nested models will be null because the SDK won't know how to resolve them (that's what the ITypeProvider is for). So I'd avoid this.

Remote Method doesn't have example in the explorer (Swagger) as the login has

As per my understanding the User/login is a built-in remote method. On the explorer (swagger) its looks with all the needed details:
but on mine remote method, i don't have all the nice information such example and more:
How can i add Example Value also for my method which accept Object
Here is my json:
"methods": {
"specifyGurdianPhone": {
"accepts": [
{
"arg": "guardianPhone",
"type": "Object",
"required": true,
"description": "{guardianPhone: \"+97255111111\"}",
"http": {
"source": "body"
}
}
],
"returns": [
{
"arg": "success",
"type": "Object",
"root": true
}
],
"description": "",
"http": {
"verb": "post"
}
It's because your param and response has "object" type. Swagger doesn't know how it looks like. To have such view you need specify model names as the type or describe possible properties one by one.
Example1:
{
"specifyGurdianPhone": {
"accepts": [
{
"arg": "guardianPhone",
"type": "string", // !!! Now, swagger know the exact type of "guardianPhone" property
"required": true
"http": {
"source": "form" // !!! Having the "form" here we say that it a property inside an object
// (it allows us to have the "string" type of the "object")
}
}
],
"returns": [
{
"arg": "success",
"type": "GuardianPhone", // !!! For example, let's return the full "GuardianPhone" instance
"root": true
}
],
"description": "",
"http": {
"verb": "post"
}
}
Example2:
{
"specifyGurdianPhone": {
"accepts": [
{
"arg": "guardianPhone",
"type": "object",
"model": "GuardianPhone" // !!! Another way to let swagger know the type of the body
// (the same will be true, if you make the type "GuardianPhone" instead of "object" and delete "model" property)
"required": true
"http": {
"source": "body"
}
}
],
"returns": [
{
...
]
}
Example3:
{
"specifyGurdianPhone": {
"accepts": [
{
"arg": "guardianPhone",
"type": "object",
"model": "GuardianPhone" // !!! Another way to let swagger know the type of the body
// (the same will be true, if you make the type "GuardianPhone" instead of "object" and delete "model" property)
"required": true
"http": {
"source": "body"
}
}
],
"returns": [
{
"arg": "success",
// !!! Instead of a model name you can describe properties one by one,
// but this trick will not work with arrays (it's true for "accepts" also)
// !!! WARNING You need strong-remoting v3.15.0 or higher due to https://github.com/strongloop/loopback/issues/3717 for this approach
"type": {
"id": {"type": "string", "description": "An id property"},
"guardianPhone": {"type": "string"}
},
"root": true
}
],
"description": "",
"http": {
"verb": "post"
}
}

ElasticSearch (AWS): How to use another index as a query/match parameter?

Basically I am trying to implement this strategy.
Sample Data:
PUT /newsfeed_consumer_network/consumer_network/urn:viadeo:member:me
{
"producerIds": [
"urn:viadeo:member:ned",
"urn:viadeo:member:john",
"urn:viadeo:member:mary"
]
}
PUT /newsfeed/news/urn:viadeo:news:33
{
"producerId": "urn:viadeo:member:john",
"published": "2014-12-17T12:45:00.000Z",
"actor": {
"id": "urn:viadeo:member:john",
"objectType": "member",
"displayName": "John"
},
"verb": "add",
"object": {
"id": "urn:viadeo:position:10",
"objectType": "position",
"displayName": "Software Engineer # Viadeo"
},
"target": {
"id": "urn:viadeo:profile:john",
"objectType": "profile",
"displayName": "John's profile"
}
}
Sample Query:
POST /newsfeed/news/_search
{
"query": {
"bool": {
"must": [{
"match": {
"actor.id": {
"producerId": {
"index": "newsfeed_consumer_network",
"type": "consumer_network",
"id": "urn:viadeo:network:me",
"path": "producerIds"
}
}
}
}]
}
}
}
I am getting the following error:
"type": "query_parsing_exception",
"reason": "[match] query does not support [index]"
How can I use an index to support a matching query? Is there any way to implement this?
Basically I just want to use another document as the source of the matching parameter for my query. Is this even possible with ElasticSearch?