Модель на стороне клиента, эквивалентная родительской модели на стороне сервера - PullRequest
0 голосов
/ 20 декабря 2018

Автоматическая генерация клиентской модели на основе документа open api 3.0 на стороне сервера не производит эквивалент родительского класса orm на стороне сервера.

Я разрабатываю новый сервер акведука и хочу иметь клиент браузерамодель автоматически генерируется из серверной модели.Я создал класс модели LanguageLevel и класс модели LanguageLesson, где у LanguageLevel много LanguageLesson.Я создал два соответствующих контроллера и операции getAllLevels, createLanguageLevel и getAllLessons соответственно.Затем я создал файл миграции, а также файл документа open api 3.0.Я использовал утилиту генерирования open 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", "info": {"title": "back_end", "description": "Seven Arabic Server.", "версия": "0.0.1"}, "серверы": [{"url": "http://localhost:8888"}]," пути ": {" / level ": {" параметры ": [],"get": {"tags": ["Levels"], "operationId": "getAllLevels", "parameters": [{"name": "sequence", "in": "query", "required": false, "allowEmptyValue": false, "schema": {"type": "integer"}}], "answers": {"200": {"description": "Успешный ответ."}}}, "post":{"tags": ["Levels"], "operationId": "createLanguageLevel", "параметры ": []," requestBody ": {" required ": true," content ": {" application / json ": {" schema ": {" $ ref ":" # / components / schemas / LanguageLevel "}}}}, "response": {"200": {"description": "Успешный ответ."}}}}, "/ level / {sequence}": {"parameters": [{"name": "sequence", "in": "путь", "обязательный": истина, "схема": {"тип": "строка"}}]}, "/ уроки": {"параметры": [], "получить": {"tags": ["Lessons"], "operationId": "getAllLessons", "parameters": [{"name": "id", "in": "query", "required": false, "allowEmptyValue":false, "схема": {"тип": "целое число"}}], "ответы": {"200": {"описание": "успешный ответ."}}}}, "/ уроки / {идентификатор}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"тип": "строка"}}]}, "/ пример": {"параметры": []}}, "компоненты": {"schemas": {"LanguageLesson": {"title": "LanguageLesson","type": "object", "properties": {"pk": {"title": "pk", "type": "integer", "description": "Это основной идентификатор для этого объекта. \ n"," nullable ": false}," sequence ": {" title ":" sequence "," type ":" integer "," nullable ": false}," languageLevel ": {" title ":" languageLevel ","type": "object", "properties": {"pk": {"type": "integer"}}}}, "description": ""}, "LanguageLevel": {"title": "LanguageLevel", "type": "object", "properties": {"pk": {"title": "pk", "type": "integer", "description": "Это основной идентификатор этого объекта. \n "," nullable ": false}," sequence ": {" title ":" sequence "," type ":" integer "," description ":" Никакие два объекта не могут иметь одинаковое значение для этого поля. \ n"," nullable ": false}," languageLessons ": {" type ":" array "," items ": {" $ ref ":" # / components / schemas / LanguageLesson "}," nullable ": true,"доступен только для чтения ":true}}, "description": ""}}, "response": {}, "parameters": {}, "requestBodies": {}, "headers": {}, "securitySchemes": {}, "callbacks": {}}}

Обратите внимание, что 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": ""
        }

Модель с открытым клиентским интерфейсом, созданная API (показан только LanguageLevel)

class 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 голосов
/ 22 декабря 2018

Я решил проблему, заменив спецификацию «languageLevel» на {«$ ref»: «# / components / schemas / LanguageLevel»} в соответствии со спецификацией Open API 3.0.2.Теперь, когда я запускаю openapi-generate-cli для файла спецификации, я получаю правильный класс LanguageLevel следующим образом:

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

}

Iтеперь также есть свойства sequence и languageLessons.

Поскольку Aqueduct генерирует файл спецификации открытого API, мы можем с уверенностью сказать, что это проблема Aqueduct, когда в разделе компонентов он создает другого родителя.определение в дочернем определении вместо ссылки родительского свойства на уже определенный родительский.(Примечание. Однако оно ссылается на свойство дочернего массива в родительском классе на определенный дочерний.)

0 голосов
/ 20 декабря 2018

С таким форматированием действительно трудно читать, но модели правильно определены в ваших компонентах схемы.Свойство languageLevel в вашем типе LanguageLesson опирается на столбец внешнего ключа.Поведение по умолчанию при извлечении LanguageLesson будет состоять в том, чтобы заполнять только объект с первичным ключом.

Если вы планируете иметь конечную точку, в которой вы присоединяете полный объект LanguageLevel к LanguageLesson, вам необходимо переопределить ответ OpenAPI для этой конкретной конечной точки, переопределив методы в ResourceController для генерации документов.

...