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

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.

Related

Swashbuckle - add DisplayName to model properties

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; }
}

Using Java objects as request parameters breaks down to primitives in swagger ui springfox

I have the following controller code
#GetMapping("/users")
public ResponseEntity<UserDto> getUsers(Filter filter) {
return ResponseEntity.ok(userService.findUsers(filter));
}
Filter.java:
public class Filter {
private Integer page;
private Integer size;
// Contains 2 fields: "propertyName" and "order"
private Sort sort;
... getters and setters
}
The URL is following: /users?page=1&size=10&sort=+firstName. So I have a custom converter from String to Sort and it works perfectly.
However, the generated swagger documentation is incorrect:
"parameters":[
{
"name":"sort.propertyName",
"in":"query",
"required":false,
"type":"string"
},
{
"name":"sort.order",
"in":"query",
"required":false,
"type":"string",
"enum":[
"+",
"-"
]
},
{
"name":"page",
"in":"query",
"required":false,
"type":"integer",
"format":"int32"
},
{
"name":"size",
"in":"query",
"required":false,
"type":"integer",
"format":"int32"
}
]
As you can see, it has broken down the Sort field of Filter and has generated 2 parameters: sort.propertyName and sort.order. Instead, I want to have one parameter sort with type string.
Is there any way to achieve that? I have tried annotating the sort field with #ApiParam(name = "sort", value = "Sort", type = "string"), but it doesn't work.
You could create an alternate type rule that treats Sort as a String
import static springfox.documentation.schema.AlternateTypeRules.*;
...
// Configure your docket bean
new Docket(...)
...
.alternateTypeRules(newRule(Sort.class, String.class)
...

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