Swashbuckle - add DisplayName to model properties - swagger

I am using Swagger/Swashbuckle in a .NET Core app.
How can I add the display name of my model attributes in swagger.json output file?
Here my model:
public class Role
{
[DisplayName("Role Name")]
public string Name { get; set; }
public int Level { get; set; }
}
Here the current output
"Role": {
"properties": {
"Name": {
"type": "string"
},
"Level": {
"format": "int32",
"type": "integer"
}
}
}
Here the desired output:
"Role": {
"properties": {
"Name": {
"displayName": "Role Name",
"type": "string"
},
"Level": {
"displayName": "Level",
"format": "int32",
"type": "integer"
}
}
}

Like I mentioned in my comments the "displayName" is not in the specifications
Latest:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
Older version:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
I just added that to one of my files to see what will happen during validation:
https://validator.swagger.io/validator/debug?url=https://raw.githubusercontent.com/heldersepu/hs-scripts/master/swagger/56287697_swagger_aws.json
We can see the validator does not like that, we get an error:
{
"schemaValidationMessages": [ {
"level": "error",
"domain": "validation",
"keyword": "additionalProperties",
"message": "object instance has properties which are not allowed by the schema: [\"displayName\"]",
"schema": {
"loadingURI": "http://swagger.io/v2/schema.json#", "pointer": "/definitions/schema"
}
,
"instance": {
"pointer": "/definitions/MyData/properties/name"
}
}
]
}
You could propose that change to the specification but don't expect it to get added any time soon:
https://github.com/OAI/OpenAPI-Specification/issues
The only quick option or workaround I see, will be using extensions:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#specification-extensions
You can inject those using an IDocumentFilter:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/search?q=IDocumentFilter
Look like the IDocumentFilter has some breaking changes on the latest version:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/2b171c0fc6efe40f3a29a45c48d6b01221a0c214/README.md#document-filters
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/2b171c0fc6efe40f3a29a45c48d6b01221a0c214/README-v5.md#document-filters
Your desired output will change a bit:
"Role": {
"properties": {
"Name": {
"x-displayName": "Role Name",
"type": "string"
},
"Level": {
"x-displayName": "Level",
"format": "int32",
"type": "integer"
}
}
}

Instead of using DisplayName() attribute, you can use JsonPropertyName() attribute which is out of the box.
public class Role
{
[JsonPropertyName("Role Name")]
public string Name { get; set; }
public int Level { get; set; }
}

Related

Displaying enum values together with a referenced class in Swagger using Swashbuckle

I am using Swashbuckle to generate Swagger output. On my model I the following property:
public FieldValue? MyProperty { get; set; }
FieldValue is a simple class that can hold an ID and a name:
public class FieldValue
{
/// <summary>
/// The numerical represenation of the value.
/// </summary>
/// <example>1</example>
public string Id { get; set; }
/// <summary>
/// The textual represenation of the value.
/// </summary>
/// <example>SomeValue</example>
public string Name { get; set; }
}
Via some business logic in our code, a set of possible key-value pairs (ID and name) are mapped to this property.
Now, I would like to show all the possible values for MyProperty in the enum tag in my Swagger output. Using an implementation of ISchemaFilter, a custom attribute on the MyProperty property and using allOf instead of a simple ref, I have managed to add the values in my JSON output, see below. The reason for using allOf instead of just ref is that ref will overwrite all properties on the referencing schema. So, when I use allOf it keeps my description and enum fields in the document.
{
"components": {
"schemas": {
"FieldValue": {
"type": "object",
"properties": {
"Id": {
"type": "string",
"description": "The numerical represenation of the value.",
"nullable": true,
},
"Name": {
"type": "string",
"description": "The textual represenation of the value.",
"nullable": true,
}
}
},
"MyProperty": {
"enum": [
"1: EnumValue1",
"2: EnumValue2",
"3: EnumValue3"
],
"allOf": [{
"$ref": "#/components/schemas/FieldValue"
}
],
"description": "Some description",
"nullable": true
}
}
}
This does not show the enum-values in the Swagger UI, though. It does show the description.
Is this Swagger doc valid? If not, how can I make it valid and display the enums for MyProperty?
The correct representation of your use case is:
"MyProperty": {
"enum": [
{"Id": "1", "Name": "EnumValue1"},
{"Id": "2", "Name": "EnumValue2"},
{"Id": "3", "Name": "EnumValue3"}
],
"allOf": [
{ "$ref": "#/components/schemas/FieldValue" }
],
"description": "Some description",
"nullable": true
}
However, there's little to no tooling support for enums containing object literals. I suggest mentioning the possible Id and Name values in the description of the MyProperty property.

GeoJson polygons from MVC controller to gmaps.js through ajax

I'm trying to send a few polygons from a controller to a ajax request on the view.
I'm using gmaps.js on client side. And I'm trying to follow the GeoJson specs for polygon object. Here is my raw object:
[
{
"type" : "POLYGON",
"id" : null,
"geometry" :
[
[
[25.24718989858574, 55.34980773925781],
[25.24715108267782, 55.34893870353699],
[25.24763628063545, 55.34891724586487],
[25.247869174966873, 55.34907817840576],
[25.247869174966873, 55.34965753555298],
[25.24767509638834, 55.34981846809387]
]
]
},
{
"type" : "POLYGON",
"id" : null,
"geometry" :
[
[
[25.248684301611156, 55.34983992576599],
[25.248480520462763, 55.349721908569336],
[25.24788858280767, 55.34993648529053],
[25.247578056982842, 55.35008668899536],
[25.247354866056035, 55.35041928291321],
[25.246830850964393, 55.35105228424072],
[25.2466755867995, 55.35133123397827],
[25.24611275253863, 55.35210371017456],
[25.24532672101826, 55.353219509124756],
[25.24626801742273, 55.35389542579651],
[25.24648150631442, 55.354024171829224],
[25.248655190039447, 55.3501296043396]
]
]
},
{
"type" : "POLYGON",
"id" : null,
"geometry" :
[
[
[25.246190385005487, 55.35040855407715],
[25.246190385005487, 55.35080552101135],
[25.246374761915458, 55.35084843635559],
[25.24653002646476, 55.35092353820801],
[25.24661736268653, 55.35104155540466],
[25.24703463487969, 55.350472927093506],
[25.246918186969957, 55.35039782524109]
]
]
},
{
"type" : "POLYGON",
"id" : null,
"geometry" :
[
[
[25.24541891016349, 55.350982546806335],
[25.24540920604625, 55.35240948200226],
[25.24495311166098, 55.352463126182556],
[25.244967667891192, 55.350998640060425]
]
]
},
{
"type" : "POLYGON",
"id" : null,
"geometry" :
[
[
[25.245229679737204, 55.35044610500336],
[25.245244235934287, 55.35085916519165],
[25.246098196445583, 55.35085916519165],
[25.24614671674897, 55.3508323431015],
[25.24614671674897, 55.35039246082306],
[25.24603997205592, 55.35036027431488]
]
]
}
]
To represent one polygon, I have this class on server side:
public class TempPolygon
{
public string Type { get; set; }
public string Id { get; set; }
public List<Tuple<decimal, decimal>> Geometry { get; set; }
public TempPolygon()
{
Type = "POLYGON";
Id = null;
}
}
Now the action will return a List<TempPolygon> as JsonResult but I'm not able to figure out if my definition of the TempPolygon class is correctly reflecting the GeoJson. Also if I paste the Json on http://json2csharp.com/, I get this class:
public class RootObject
{
public string type { get; set; }
public object id { get; set; }
public List<List<List<double>>> geometry { get; set; }
}
The List<List<List<double>>> makes no sense as clearly, latitude and longitude are pairs. How do i define my class's Geometry property to reflect the specs of GeoJson

Move items around within object in JSON

Have some JSON
{
"Items": [
{
"Name": "Hello",
"Id": 1
}
{
"Name": "World",
"Id": 2
}
}
And for various reasons (mainly cos people need to edit the file (don't ask)) would really like to move "Id" to before "Name".
{
"Items": [
{
"Id": 1,
"Name": "Hello"
}
{
"Id": 2,
"Name": "World"
}
}
We're using Json.NET - any suggestions on how to achieve this?
As mentioned here, use the JsonPropertyAttribute and the Order property.
public class SomeClass
{
[JsonProperty(Order=2)]
public string Name {get; set;}
[JsonProperty(Order=1)]
public int Id {get; set;}
}
Should appear as:
{
"Id":0,
"Name":null
}

Breeze# executeQuery returns empty objects

I have Breeze.Sharp application which communicates with legacy WebAPI which doesn't provide metadata.
Query seems to be executed properly - expected number of objects is returned but all of them are empty. Modifying query parameters also works - number of returned objects changes as expected. I was playing around with EntityManager.MetadataStore but nothing helped.
Here is the final code I'm currently using to communicate with WebAPI.
public class DokumentModelBreeze: BaseEntity
{
public string id { get; set; }
public string numer { get; set; }
public decimal suma { get; set; }
}
...
Configuration.Instance.ProbeAssemblies(typeof(DokumentModelBreeze).Assembly);
var manager = new EntityManager("http://localhost:52357/api/");
manager.DataService.HasServerMetadata = false;
var store = manager.MetadataStore;
store.SetResourceName("dokumenty", typeof(DokumentModelBreeze), true);
store.NamingConvention = new CamelCasePropertiesNamingConvention();
var builder = new EntityTypeBuilder<DokumentModelBreeze>(store);
builder.DataProperty(d => d.id).IsPartOfKey();
using(TextWriter writer = File.CreateText("C:/metadata.txt")) {
store.ExportMetadata(writer);
var query = new EntityQuery<DokumentModelBreeze>("dokumenty");
query = query.WithParameter("nrFirmy", 1).Where(p => p.numer=="123");
var results = await manager.ExecuteQuery<DokumentModelBreeze>(query);
List<DokumentModelBreeze> Dokumenty = new List<DokumentModelBreeze>();
foreach(var item in results)
Dokumenty.Add(item);
In the last foreach loop every item is of type DokumentModelBreeze but each member property equals to null or 0 respectively.
I have saved MetadataStore to file, it is included below:
{
"metadataVersion": "1.0.3",
"namingConvention": {
"clientServerNamespaceMap": {},
"name": "camelCaseProperties"
},
"structuralTypes": [
{
"shortName": "BaseEntity",
"namespace": "Breeze.Sharp",
"baseTypeName": "",
"autoGeneratedKeyType": "None"
},
{
"shortName": "DokumentModelBreeze",
"namespace": "BRuNETWPF.ViewModels",
"baseTypeName": "BaseEntity:#Breeze.Sharp",
"autoGeneratedKeyType": "None",
"defaultResourceName": "dokumenty",
"dataProperties": [
{
"name": "id",
"dataType": "String",
"isNullable": false,
"defaultValue": "",
"isPartOfKey": true
},
{
"name": "numer",
"dataType": "String",
"isNullable": false,
"defaultValue": ""
},
{
"name": "suma",
"dataType": "Decimal",
"isNullable": false,
"defaultValue": 0.0
}
]
}
],
"resourceEntityTypeMap": {
"dokumenty": "DokumentModelBreeze:#BRuNETWPF.ViewModels"
}
}
Am I missing something here or perhaps Breeze# doesn't allow to query WebAPI without metadata ?
The same code executed against test WebAPI with exposed metadata works well.
Your GetValue and SetValue properties must be defined like so:
public string id
{
get { return GetValue<string>("id"); }
set { SetValue(value); }
}
It's a pain, I know, but this fixed it for me after one of our awesome tech leads pointed it out :)

Custom Web API Formatting

I've been playing around with asp.net web api, and I noticed that default generated returned json doesn't include the object level key. I was also wondering how to customize the output of the json string. For example:
Getting a User usually returns
{
"Name": "ChaoticLoki",
"Age": 22,
"Sex": "Male"
}
I was hoping I could return something like:
{
"data": {
"Name": "ChaoticLoki",
"Age": 22,
"Sex": "Male",
},
"success": true
}
You can then create a class wrapping the data and status like this
public class JsonResult{
public object data { get; set;}
public boolean success { get; set;}
}
And then in your Web Api methods, you can do
var data = ... //getting from repo
return Json(new JsonResult{data = data, success = true});

Resources