与服务器端orm父模型等效的客户端模型

时间:2018-12-20 00:24:09

标签: aqueduct

基于服务器端打开的api 3.0文档自动生成客户端模型不会产生与服务器端orm父类等效的结果。

我正在开发新的渡槽服务器,并希望从服务器端模型自动生成浏览器客户端模型。我创建了一个LanguageLevel模型类和一个LanguageLesson模型类,其中LanguageLevel有许多LanguageLesson。我分别创建了两个相应的控制器和getAllLevels,createLanguageLevel和getAllLessons操作。然后,我创建了迁移文件以及打开的api 3.0文档文件。我使用了开放式api生成实用程序来创建客户端库。

这是针对渡槽CLI和项目版本3.1.0 + 1。以下结果与版本3.0.2相同。对于客户端模型生成,使用了openapi-generator-cli-3.3.4。

服务器端

类LanguageLevel扩展了ManagedObject <_LanguageLevel>实现_LanguageLevel {}

_LanguageLevel类{

@primaryKey
int pk;

@Column(unique: true)
int sequence;

ManagedSet<LanguageLesson> languageLessons;

}

LanguageLesson类扩展ManagedObject <_LanguageLesson>实现_LanguageLesson {}

_LanguageLesson类{

@primaryKey
int pk;

@Column()
int sequence;

@Relate(#languageLessons)
LanguageLevel languageLevel;

}

使用命令:渡槽文档打开api 3.0

{     “ openapi”:“ 3.0.0”,     “信息”:{         “ title”:“ back_end”,         “ description”:“七个阿拉伯语服务器。”,         “版本”:“ 0.0.1”     },     “服务器”:[{         “ url”:“ http://localhost:8888”     }],     “路径”:{         “ /级别”:{             “参数”:[],             “获取”:{                 “标签”:[“级别”],                 “ operationId”:“ getAllLevels”,                 “参数”:[{                     “ name”:“ sequence”,                     “ in”:“查询”,                     “必填”:false,                     “ allowEmptyValue”:否,                     “模式”:{                         “ type”:“整数”                     }                 }],                 “响应”:{                     “ 200”:{                         “ description”:“成功响应。”                     }                 }             },             “帖子”:{                 “标签”:[“级别”],                 “ operationId”:“ createLanguageLevel”,                 “参数”:[],                 “ requestBody”:{                     “必填”:是,                     “内容”:{                         “ application / json”:{                             “模式”:{                                 “ $ ref”:“#/ components / schemas / LanguageLevel”                             }                         }                     }                 },                 “响应”:{                     “ 200”:{                         “ description”:“成功响应。”                     }                 }             }         },         “ / levels / {sequence}”:{             “参数”:[{                 “ name”:“ sequence”,                 “ in”:“路径”,                 “必填”:是,                 “模式”:{                     “ type”:“字符串”                 }             }]         },         “ /课程”:{             “参数”:[],             “获取”:{                 “标签”:[“经验”],                 “ operationId”:“ getAllLessons”,                 “参数”:[{                     “ name”:“ id”,                     “ in”:“查询”,                     “必填”:false,                     “ allowEmptyValue”:否,                     “模式”:{                         “ type”:“整数”                     }                 }],                 “响应”:{                     “ 200”:{                         “ description”:“成功响应。”                     }                 }             }         },         “ /课程/ {id}”:{             “参数”:[{                 “ name”:“ id”,                 “ in”:“路径”,                 “必填”:是,                 “模式”:{                     “ type”:“字符串”                 }             }]         },         “ / example”:{             “参数”:[]         }     },     “组件”: {         “方案”:{             “ LanguageLesson”:{                 “ title”:“ LanguageLesson”,                 “ type”:“对象”,                 “属性”:{                     “ pk”:{                         “ title”:“ pk”,                         “ type”:“整数”,                         “ description”:“这是该对象的主要标识符。\ n”,                         “可为空”:false                     },                     “顺序”: {                         “ title”:“ sequence”,                         “ type”:“整数”,                         “可为空”:false                     },                     “ languageLevel”:{                         “ title”:“ languageLevel”,                         “ type”:“对象”,                         “属性”:{                             “ pk”:{                                 “ type”:“整数”                             }                         }                     }                 },                 “说明”:“”             },             “ LanguageLevel”:{                 “ title”:“ LanguageLevel”,                 “ type”:“对象”,                 “属性”:{                     “ pk”:{                         “ title”:“ pk”,                         “ type”:“整数”,                         “ description”:“这是该对象的主要标识符。\ n”,                         “可为空”:false                     },                     “顺序”: {                         “ title”:“ sequence”,                         “ type”:“整数”,                         “ description”:“该字段的两个对象都不能具有相同的值。\ n”,                         “可为空”:false                     },                     “ languageLessons”:{                         “ type”:“ array”,                         “项目”:{                             “ $ ref”:“#/ components / schemas / LanguageLesson”                         },                         “ nullable”:是的,                         “ readOnly”:是                     }                 },                 “说明”:“”             }         },         “响应”:{},         “参数”:{},         “ requestBodies”:{},         “标题”:{},         “ securitySchemes”:{},         “回调”:{}     } }

请注意languageLevel仅定义为具有“ pk”属性的对象类型,而LanguageLevel定义为具有“ pk”,“ sequence”和“ languageLessons”的对象类型。从规格中提取出来的样子:

                "languageLevel": {
                    "title": "languageLevel",
                    "type": "object",
                    "properties": {
                        "pk": {
                            "type": "integer"
                        }
                    }
                }

        "LanguageLevel": {
            "title": "LanguageLevel",
            "type": "object",
            "properties": {
                "pk": {
                    "title": "pk",
                    "type": "integer",
                    "description": "This is the primary identifier for this object.\n",
                    "nullable": false
                },
                "sequence": {
                    "title": "sequence",
                    "type": "integer",
                    "description": "No two objects may have the same value for this field.\n",
                    "nullable": false
                },
                "languageLessons": {
                    "type": "array",
                    "items": {
                        "$ref": "#/components/schemas/LanguageLesson"
                    },
                    "nullable": true,
                    "readOnly": true
                }
            },
            "description": ""
        }

Open API生成的客户端模型(仅显示LanguageLevel)

类LanguageLevel {

int pk = null;
LanguageLevel();

@override
String toString() {
  return 'LanguageLevel[pk=$pk, ]';
}

LanguageLevel.fromJson(Map<String, dynamic> json) {
    if (json == null) return;
    pk = json['pk'];
}

Map<String, dynamic> toJson() {
    return {
       'pk': pk
    };
}

static List<LanguageLevel> listFromJson(List<dynamic> json) {
    return json == null ? new List<LanguageLevel>() : json.map((value) => 
    new LanguageLevel.fromJson(value)).toList();
}

static Map<String, LanguageLevel> mapFromJson(Map<String, dynamic> json) {
    var map = new Map<String, LanguageLevel>();
    if (json != null && json.length > 0) {
        json.forEach((String key, dynamic value) => map[key] = new 
        LanguageLevel.fromJson(value));
    }
    return map;
}

}

除了所有必需的代码外,它还创建了LanguageLevel和LanguageLesson模型类。 LanguageLesson模型看起来不错,因为它具有预期的属性以及对LanguageLevel的引用。但是LanguageLevel仅具有服务器端模型的@primarykey等效项。因此,目前无法显示生成的代码中的LanguageLevel对象。我希望在这一阶段能够做到这一点。

2 个答案:

答案 0 :(得分:0)

使用这种格式确实很难阅读,但是模型是在架构组件中正确定义的。 LanguageLesson类型中的languageLevel属性由外键列支持。当您获取LanguageLesson时,默认行为是只填充主键的对象。

如果您打算在端点上将整个LanguageLevel对象与LanguageLesson结合在一起,则需要通过重写ResourceController中用于生成文档的方法来覆盖该特定端点的OpenAPI响应。

答案 1 :(得分:0)

我已按照Open API规范3.0.2的要求,用{“ $ ref”:“#/ components / schemas / LanguageLevel”}替换了“ languageLevel”规范,从而解决了该问题。现在,当我对规范文件运行openapi-generate-cli时,将获得正确的类LanguageLevel,如下所示:

类LanguageLevel {

int pk = null;
int sequence = null;

List<LanguageLesson> languageLessons = [];
LanguageLevel();

@override
String toString() {
    return 'LanguageLevel[pk=$pk, sequence=$sequence, languageLessons=$languageLessons, ]';
}

LanguageLevel.fromJson(Map<String, dynamic> json) {
    if (json == null) return;
    pk = json['pk'];
    sequence = json['sequence'];
    languageLessons = LanguageLesson.listFromJson(json['languageLessons']);
}

Map<String, dynamic> toJson() {
    return {
      'pk': pk,
      'sequence': sequence,
      'languageLessons': languageLessons
    };
}

static List<LanguageLevel> listFromJson(List<dynamic> json) {
    return json == null ? new List<LanguageLevel>() : json.map((value) => new LanguageLevel.fromJson(value)).toList();
}

static Map<String, LanguageLevel> mapFromJson(Map<String, dynamic> json) {
    var map = new Map<String, LanguageLevel>();
    if (json != null && json.length > 0) {
        json.forEach((String key, dynamic value) => map[key] = new LanguageLevel.fromJson(value));
    }
    return map;
}

}

我现在也具有sequence和languageLessons属性。

由于打开的api规范文件是由Aqueduct生成的,因此我们可以放心地说这是Aqueduct的问题,在组件部分中,它将在子定义中创建另一个父定义,而不是将parent属性引用到已经定义的父级。 (注意:但是,它将父类中的子数组属性引用到已定义的子项。)