I am exposing my API using OpenAPI 3.0. One of the models that I created was extended from org.springframework.hateoas.RepresentationModel. The model can be seen under the /components/schemas/ correctly with all the properties I created. However, the inherited property
private final List<Link> links;
are created with error
Links: {
title: "Links",
type: "object",
properties: {
links: {
type: "array",
items: {
$ref: "Error-ModelName{namespace='org.springframework.hateoas', name='Link'}"
}
}
}
}
Not sure how would I be able to fix this as this third-party lib. Please advise.
Related
I am trying to use swagger within my NestJS application and I am not able to define a custom class to be used for the additionalProperties typing.
I have a custom class:
#ApiExtraModels(Entity)
export class Entity {
#ApiProperty({description:"Map of the entities"}) entityID: string;
}
After this, I checked that the schema path(which should be defined by using the ApiExtraModels decorator) is defined - the console log...
console.log("getSchemaPath", getSchemaPath('Entity'));
...indeed has the output of:
getSchemaPath #/components/schemas/Entity
After this code, I tried to use this schema as a type for additional properties as such:
export class EntityLevel {
#ApiProperty({description:"Generic name of the entities in the current level"})
levelName: string;
#ApiProperty({
description:"Map object of the Entities - [GUID: string]: Entity",
type: 'object',
additionalProperties: {$ref: getSchemaPath('Entity')}
})
levelEntities: Map<string, Entity>;
}
But the output on the swagger for the given object is:
{
"levelName": "string",
"levelEntities": {}
}
My current workaround is to delete the #ApiExtraModels decorator and add a dummy property of type Entity to another class and then it works as it should(with a dummy property I do not want to have of course):
export class RandomClass {
id: String;
#ApiPropertyOptional({
description: "This is a dummy entity added as a workaround for not being able to include Entity type otherwise",
type: Entity
})
dummyEntity?: Entity;
}
Then the swagger for the object is as desired:
{
"levelName": "string",
"levelEntities": {
"additionalProp1": {
"entityID": "string"
},
"additionalProp2": {
"entityID": "string"
},
"additionalProp3": {
"entityID": "string"
}
}
}
What am I doing wrong when trying to define the ExtraModel with the #ApiExtraModels decorator?
as mentioned in issue #738, the ApiExtraModels is to be used on top of a method, not on top of the model class.
Therefore your solution should be:
export class Entity {
#ApiProperty({description:"Map of the entities"}) entityID: string;
}
#ApiExtraModels(Entity)
export class EntityLevel {
#ApiProperty({description:"Generic name of the entities in the current level"})
levelName: string;
#ApiProperty({
description:"Map object of the Entities - [GUID: string]: Entity",
type: 'object',
additionalProperties: {$ref: getSchemaPath(Entity)}
})
levelEntities: Map<string, Entity>;
}
another way is by defining the extra models at main.ts:
SwaggerModule.createDocument(app, config, {
extraModels: [.......]
});
In my case, i need the extra models to be put in { oneOf: [] }. This can be easily solved by listing the extra models inside ApiExtraModels annotation, such as:
#ApiExtraModels(EntityA, EntityB)
export class EntityLevel {
...
}
TL;DR
How do I create a Model that includes nested Objects without creating a new Model for every property that is of type Object?
New to LB4 & Typescript so apologies if this is an obv question. I want to create a Model which represents a Response that includes a nested Object for my endpoint. Here is a sample response:
{
"result": {
"prop1": "blah blah",
"prop2": {
"subProp": {
"subSubProp": "blah blah"
}
}
}
}
Problem I have is representing the nested object inside of my Model. Ideally I would do something like this:
#model()
export class MyResponseModel extends Model {
#property({
type: 'object'
})
result: {
prop1: string,
prop2: {
subProp: {
subSubProp: string
}
}
}
}
Then in my controller I would set this as the response type:
#post('/my-endpoint', {
responses: {
...,
schema: {
'x-ts-type': MyResponseModel,
}
}
})
async post(): Promise<MyResponseModel>{...}
The only way I have got this working so far is creating a Model for every nested object i.e. a Model for "result", another for "prop2" and another for "subProp" which doesn't feel is the right way to implement this? In LB3 it looks like you can specify a "properties" prop to define child objects which can also have sub objects.
Same q asked for LB3 but doesn't answer it for LB4: loopback model with object
Asked in google group with no answer: https://groups.google.com/forum/?nomobile=true#!topic/loopbackjs/AKgZT6V-pCc
Thanks in advance!
How do I create a Model that includes nested Objects without creating a new Model for every property that is of type Object?
Same q asked for LB3 but doesn't answer it for LB4: loopback model with object
The solution described in the answer to your LB3 question should work in LoopBack 4.
#model()
export class MyResponseModel extends Model {
#property({
type: {
prop1: 'string',
prop2: {
type: {
subSubProp: 'string'
}
}
}
})
result: {
prop1: string,
prop2: {
subProp: {
subSubProp: string
}
}
}
}
A short-hand notation should work too:
#model()
export class MyResponseModel extends Model {
#property({
prop1: 'string',
prop2: {
subSubProp: 'string'
}
})
result: {
prop1: string,
prop2: {
subProp: {
subSubProp: string
}
}
}
}
I'm having trouble to find how to mark required members of complex objects I use as parameters for my actions using Swashbuckle.AspNetCore (latest version available through nuGet package manager) in a .NET Core WebAPI project.
I have implemented a custom IOperationFilter that adds a required = true flag for the action parameters but obviously it does not go through the complex objects definition so all their members are still marked as optional.
What I would like to obtain is this:
definitions:
ComplexObjectParameters:
description: 'my complex object parameter'
type: object
required: ['parameter1', 'parameter2']
properties:
parameter1:
type: string
parameter2:
type: string
parameter3:
type: string
Do you have any idea how I could implement this?
EDIT: a demo project demonstrating my issue is available here: https://github.com/albator1932/ComplexObjects
Use an IDocumentFilter and add [Required] to the fields that are required:
internal class AddComplexObjectRequiredParameter : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
if (swaggerDoc.Definitions != null)
{
if (swaggerDoc.Definitions["ComplexObjectParameters"].Required == null)
swaggerDoc.Definitions["ComplexObjectParameters"].Required = new List<string>();
foreach (var field in typeof(ComplexObjectParameters).GetFields())
{
if (Attribute.IsDefined(field, typeof(RequiredAttribute)))
swaggerDoc.Definitions["ComplexObjectParameters"].Required.Add(field.Name);
}
}
}
}
I'm trying to fetch a model schema for an item in Swagger. I'd like to do this through an http request from a different machine from the one hosting Swagger.
I can fetch the Swagger API-docs as json from:
domain.com/swagger/v2/api-docs.json
The response contains:
{
"swagger": "2.0",
...
paths: {
"/endpoint": {
"get": {
...
"responses": {
"200":{
"description":"OK",
"schema": {
"type":"array",
"items": {
"$ref":"#/definitions/Item"
}
}
}
}
}
}
}
}
Is there any way to fetch the "/definitions/Item" model schema?
I'd like to do an http GET on something like:
domain.com/swagger/v2/api-docs/definitions/Item.json
I'm using Swagger version 2.0.
Thanks
It's at the bottom of the same document. Eg: if you go to the live demo of the swagger editor (http://editor.swagger.io/#/edit) and scroll to the bottom you'll see the object definitions that are referenced in the endpoint definitions.
I work in durandal project and use breeze entities.
In my project, I need to create client entity, and on the creating, give initialValues.
Normally, whant you want to give initialValues to new entity, you pass it to createEntity function.
For example:
dataContext.createEntity('employee', {age:40, city:'OurCity'});
So you get new empty instance of employee with default data for age and city.
I want to do it with entity type that contain complexFields.
But it doesn't work.
My entity is client-entity.
Here is the code:
addFormType(store);
function addFormType(store) {
store.addEntityType({
shortName: "FormDTO",
autoGeneratedKeyType: AutoGeneratedKeyType.Identity,
dataProperties: {
key: {//auto primary key. numeratorA and Code cannot be key, becose for new records thier aren't unique
dataType: DataType.Int32, isNullable: false, isPartOfKey: true
}
TaxYear: {
dataType: DataType.String, validators: [Validator.required({ message: 'דרוש' })]
},
Unit_A: {
name: "FormUnit_A",
complexTypeName: 'FormUnit_A:#'
}
}
});
store.registerEntityTypeCtor("FormDTO", null, FormInit);
}
function FormInit(entity) {
validationHelper.initializer(entity);
}
addFormUnit_AType(store);
function addFormUnit_AType(store) {
store.addEntityType({
shortName: "FormUnit_A",
isComplexType: true,
dataProperties: {
CompanyName: {
dataType: DataType.String
},
CompanyAddress: {
dataType: DataType.String
}
}
});
store.registerEntityTypeCtor("FormUnit_A", null, null);
}
I tried to initial it by the follwing rows:
var defaultData = {
TaxYear:0,
Unit_A:{
CompanyName:'ourCompany',
CompanyAddress:'Zar 200 OurCity'
}
};
clientManager.createEntity('FormDTO', defaultData);
But it throws exception: "Object doesn't support property or method 'getProperty'"
I tried also to pass an One-layer object with all of the properties:
var defaultData = {
TaxYear:0,
CompanyName:'ourCompany',
CompanyAddress:'Zar 200 OurCity'
};
clientManager.createEntity('FormDTO', defaultData);
But it throws exception:Object doesn't support property or method 'CompanyName'
So what is the correct way to create-entity with initialValues whan entity contain complex type?
Based of what is working in your project it sounds like you are using something like a camelCase strategy for naming your client side properties. If that is not the case please excuse this answer.
If that is the case then why aren't you using camelCased properties when creating your complex types? Seems simple enough -
var defaultData = {
taxYear:0,
unit_A:{
companyName:'ourCompany',
companyAddress:'Zar 200 OurCity'
}
};
clientManager.createEntity('FormDTO', defaultData);