From 84c0b8e439c0e132fdd5d73c18555c3b671ef7e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 5 Nov 2026 10:13:39 +0000 Subject: [PATCH 1/3] feat(API): add linked_key field to key list responses #STRINGS-4425 --- doc/compiled.json | 56 ++++++++++++++++++++++++++++++++++++ paths/keys/index.yaml | 12 ++++++++ paths/keys/search.yaml | 12 ++++++++ schemas/translation_key.yaml | 38 ++++++++++++++++++++++++ 4 files changed, 118 insertions(+) diff --git a/doc/compiled.json b/doc/compiled.json index 73278953c..dcd9dcee4 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -2880,6 +2880,44 @@ "updated_at": { "type": "string", "format": "date-time" + }, + "linked_key": { + "nullable": true, + "description": "Describes this key's role in a parent–child link relationship.\nOnly present in the response when `include_linked_keys=true` is passed.\n`null` when the key has no active link (either unlinked, or the parent\nhas been deleted).\n", + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "parent", + "child" + ], + "description": "Whether this key is the parent or the child in the link relationship.\n" + }, + "parent": { + "nullable": true, + "description": "The parent key's public identifier and name. Set for child keys; `null` for parent keys.\n", + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The parent key's public identifier (code).", + "example": "abc12345def67890abc12345def67890" + }, + "name": { + "type": "string", + "description": "The parent key's name.", + "example": "home.welcome.title" + } + } + }, + "children_count": { + "type": "integer", + "nullable": true, + "description": "The number of linked child keys. Set for parent keys; `null` for child keys.\n", + "example": 3 + } + } } }, "example": { @@ -24355,6 +24393,15 @@ "schema": { "type": "string" } + }, + { + "name": "include_linked_keys", + "in": "query", + "description": "When set to `true`, each key object in the response includes a `linked_key` field describing whether the key is a parent or child in a key-link relationship, and the number of children (for parent keys) or the parent's id and name (for child keys). Keys with no active link return `linked_key: null`. Omit this parameter or set it to `false` to leave the `linked_key` field out of the response entirely.\n", + "required": false, + "schema": { + "type": "boolean" + } } ], "responses": { @@ -24727,6 +24774,15 @@ }, { "$ref": "#/components/parameters/per_page" + }, + { + "name": "include_linked_keys", + "in": "query", + "description": "When set to `true`, each key object in the response includes a `linked_key` field describing whether the key is a parent or child in a key-link relationship, and the number of children (for parent keys) or the parent's id and name (for child keys). Keys with no active link return `linked_key: null`. Omit this parameter or set it to `false` to leave the `linked_key` field out of the response entirely.\n", + "required": false, + "schema": { + "type": "boolean" + } } ], "responses": { diff --git a/paths/keys/index.yaml b/paths/keys/index.yaml index 46cc1c029..06860617c 100644 --- a/paths/keys/index.yaml +++ b/paths/keys/index.yaml @@ -34,6 +34,18 @@ parameters: in: query schema: type: string +- name: include_linked_keys + in: query + description: > + When set to `true`, each key object in the response includes a + `linked_key` field describing whether the key is a parent or child in a + key-link relationship, and the number of children (for parent keys) or + the parent's id and name (for child keys). Keys with no active link + return `linked_key: null`. Omit this parameter or set it to `false` to + leave the `linked_key` field out of the response entirely. + required: false + schema: + type: boolean responses: '200': description: OK diff --git a/paths/keys/search.yaml b/paths/keys/search.yaml index e565c50ba..6a354595b 100644 --- a/paths/keys/search.yaml +++ b/paths/keys/search.yaml @@ -9,6 +9,18 @@ parameters: - "$ref": "../../parameters.yaml#/project_id" - "$ref": "../../parameters.yaml#/page" - "$ref": "../../parameters.yaml#/per_page" +- name: include_linked_keys + in: query + description: > + When set to `true`, each key object in the response includes a + `linked_key` field describing whether the key is a parent or child in a + key-link relationship, and the number of children (for parent keys) or + the parent's id and name (for child keys). Keys with no active link + return `linked_key: null`. Omit this parameter or set it to `false` to + leave the `linked_key` field out of the response entirely. + required: false + schema: + type: boolean responses: '200': description: OK diff --git a/schemas/translation_key.yaml b/schemas/translation_key.yaml index 7229131ad..abdb8f8b0 100644 --- a/schemas/translation_key.yaml +++ b/schemas/translation_key.yaml @@ -27,6 +27,44 @@ translation_key: updated_at: type: string format: date-time + linked_key: + nullable: true + description: | + Describes this key's role in a parent–child link relationship. + Only present in the response when `include_linked_keys=true` is passed. + `null` when the key has no active link (either unlinked, or the parent + has been deleted). + type: object + properties: + role: + type: string + enum: + - parent + - child + description: > + Whether this key is the parent or the child in the link relationship. + parent: + nullable: true + description: > + The parent key's public identifier and name. Set for child keys; + `null` for parent keys. + type: object + properties: + id: + type: string + description: The parent key's public identifier (code). + example: "abc12345def67890abc12345def67890" + name: + type: string + description: The parent key's name. + example: "home.welcome.title" + children_count: + type: integer + nullable: true + description: > + The number of linked child keys. Set for parent keys; + `null` for child keys. + example: 3 example: id: abcd1234cdef1234abcd1234cdef1234 name: home.index.headline From 2764161d4e858b71b7c0f38e0cc7537647768900 Mon Sep 17 00:00:00 2001 From: Varpuspaavi Date: Thu, 5 Nov 2026 11:52:17 +0100 Subject: [PATCH 2/3] fix(API): drop nullable on linked_key objects, update Java keys test #STRINGS-4425 The Go generator emits references to undefined Nullable types for nullable inline objects (linked_key, linked_key.parent). Remove nullable from those two objects and keep the null semantics in the descriptions. Also pass the new include_linked_keys argument in KeysApiTest for keysList and keysSearch so the Java test sources compile. Co-Authored-By: Claude Sonnet 5.5 --- .../src/test/java/com/phrase/client/api/KeysApiTest.java | 6 ++++-- doc/compiled.json | 2 -- schemas/translation_key.yaml | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/clients/java/src/test/java/com/phrase/client/api/KeysApiTest.java b/clients/java/src/test/java/com/phrase/client/api/KeysApiTest.java index ba407e1aa..0b8edc427 100644 --- a/clients/java/src/test/java/com/phrase/client/api/KeysApiTest.java +++ b/clients/java/src/test/java/com/phrase/client/api/KeysApiTest.java @@ -240,7 +240,8 @@ public void keysListTest() throws ApiException { String order = null; String q = null; String localeId = null; - List response = api.keysList(projectId, xPhraseAppOTP, page, perPage, branch, sort, order, q, localeId); + Boolean includeLinkedKeys = null; + List response = api.keysList(projectId, xPhraseAppOTP, page, perPage, branch, sort, order, q, localeId, includeLinkedKeys); // TODO: test validations } @@ -260,7 +261,8 @@ public void keysSearchTest() throws ApiException { String xPhraseAppOTP = null; Integer page = null; Integer perPage = null; - List response = api.keysSearch(projectId, keysSearchParameters, xPhraseAppOTP, page, perPage); + Boolean includeLinkedKeys = null; + List response = api.keysSearch(projectId, keysSearchParameters, xPhraseAppOTP, page, perPage, includeLinkedKeys); // TODO: test validations } diff --git a/doc/compiled.json b/doc/compiled.json index dcd9dcee4..3a4d16f8e 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -2882,7 +2882,6 @@ "format": "date-time" }, "linked_key": { - "nullable": true, "description": "Describes this key's role in a parent–child link relationship.\nOnly present in the response when `include_linked_keys=true` is passed.\n`null` when the key has no active link (either unlinked, or the parent\nhas been deleted).\n", "type": "object", "properties": { @@ -2895,7 +2894,6 @@ "description": "Whether this key is the parent or the child in the link relationship.\n" }, "parent": { - "nullable": true, "description": "The parent key's public identifier and name. Set for child keys; `null` for parent keys.\n", "type": "object", "properties": { diff --git a/schemas/translation_key.yaml b/schemas/translation_key.yaml index abdb8f8b0..fcd97c303 100644 --- a/schemas/translation_key.yaml +++ b/schemas/translation_key.yaml @@ -28,7 +28,6 @@ translation_key: type: string format: date-time linked_key: - nullable: true description: | Describes this key's role in a parent–child link relationship. Only present in the response when `include_linked_keys=true` is passed. @@ -44,7 +43,6 @@ translation_key: description: > Whether this key is the parent or the child in the link relationship. parent: - nullable: true description: > The parent key's public identifier and name. Set for child keys; `null` for parent keys. From 20c7dd3d9ef5119607948127e6ec037310cf96bd Mon Sep 17 00:00:00 2001 From: Varpuspaavi Date: Thu, 5 Nov 2026 12:17:02 +0100 Subject: [PATCH 3/3] fix(API): make linked_key nullable again with named component schemas #STRINGS-4425 linked_key is null for unlinked keys and parent/children_count are null for the opposite role, so restore nullable on the response schemas. - Move linked_key and its parent into named components (translation_key_linked_key, translation_key_linked_key_parent) with nullable: true, referenced by a plain $ref from translation_key. - Go template: render nullable model-typed fields as *Model instead of *Nullable (which is never defined). Primitives are unchanged; generated Go for the existing spec is byte-identical. Co-Authored-By: Claude Sonnet 5.5 --- doc/compiled.json | 84 +++++++++++-------- openapi-generator/templates/go/model.mustache | 2 +- schemas.yaml | 4 + schemas/translation_key.yaml | 39 +-------- schemas/translation_key_linked_key.yaml | 24 ++++++ .../translation_key_linked_key_parent.yaml | 15 ++++ 6 files changed, 98 insertions(+), 70 deletions(-) create mode 100644 schemas/translation_key_linked_key.yaml create mode 100644 schemas/translation_key_linked_key_parent.yaml diff --git a/doc/compiled.json b/doc/compiled.json index 3a4d16f8e..680ca6476 100644 --- a/doc/compiled.json +++ b/doc/compiled.json @@ -2882,40 +2882,8 @@ "format": "date-time" }, "linked_key": { - "description": "Describes this key's role in a parent–child link relationship.\nOnly present in the response when `include_linked_keys=true` is passed.\n`null` when the key has no active link (either unlinked, or the parent\nhas been deleted).\n", - "type": "object", - "properties": { - "role": { - "type": "string", - "enum": [ - "parent", - "child" - ], - "description": "Whether this key is the parent or the child in the link relationship.\n" - }, - "parent": { - "description": "The parent key's public identifier and name. Set for child keys; `null` for parent keys.\n", - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The parent key's public identifier (code).", - "example": "abc12345def67890abc12345def67890" - }, - "name": { - "type": "string", - "description": "The parent key's name.", - "example": "home.welcome.title" - } - } - }, - "children_count": { - "type": "integer", - "nullable": true, - "description": "The number of linked child keys. Set for parent keys; `null` for child keys.\n", - "example": 3 - } - } + "description": "Only returned by the list and search endpoints when `include_linked_keys=true` is passed. `null` means the key is not linked.\n", + "$ref": "#/components/schemas/translation_key_linked_key" } }, "example": { @@ -3001,6 +2969,54 @@ } ] }, + "translation_key_linked_key": { + "type": "object", + "nullable": true, + "title": "translation_key_linked_key", + "description": "Describes a key's role in a parent–child link relationship.", + "properties": { + "role": { + "type": "string", + "description": "Whether this key is the parent or the child in the link relationship.", + "enum": [ + "parent", + "child" + ] + }, + "parent": { + "$ref": "#/components/schemas/translation_key_linked_key_parent" + }, + "children_count": { + "type": "integer", + "nullable": true, + "description": "The number of linked child keys. Set for parent keys.", + "example": 3 + } + }, + "example": { + "role": "parent", + "parent": null, + "children_count": 3 + } + }, + "translation_key_linked_key_parent": { + "type": "object", + "nullable": true, + "description": "The parent key's public identifier and name. Set for child keys.", + "title": "translation_key_linked_key_parent", + "properties": { + "id": { + "type": "string", + "description": "The parent key's public identifier (code).", + "example": "abc12345def67890abc12345def67890" + }, + "name": { + "type": "string", + "description": "The parent key's name.", + "example": "home.welcome.title" + } + } + }, "affected_resources": { "type": "object", "title": "affected_resources", diff --git a/openapi-generator/templates/go/model.mustache b/openapi-generator/templates/go/model.mustache index 72bcb58af..fd7d1f116 100644 --- a/openapi-generator/templates/go/model.mustache +++ b/openapi-generator/templates/go/model.mustache @@ -34,7 +34,7 @@ type {{classname}} struct { {{#description}} // {{{description}}} {{/description}} - {{name}} {{#isNullable}}*{{/isNullable}}{{^isNullable}}{{#isBoolean}}*{{/isBoolean}}{{/isNullable}}{{{dataType}}} `{{#vendorExtensions.x-json-tag}}{{{.}}}{{/vendorExtensions.x-json-tag}}{{^vendorExtensions.x-json-tag}}json:"{{baseName}}{{^required}},omitempty{{/required}}"{{/vendorExtensions.x-json-tag}}{{#withXml}} xml:"{{baseName}}{{#isXmlAttribute}},attr{{/isXmlAttribute}}"{{/withXml}}{{#vendorExtensions.x-go-custom-tag}} {{{.}}}{{/vendorExtensions.x-go-custom-tag}}` + {{name}} {{#isNullable}}*{{/isNullable}}{{^isNullable}}{{#isBoolean}}*{{/isBoolean}}{{/isNullable}}{{#isModel}}{{#isNullable}}{{{complexType}}}{{/isNullable}}{{^isNullable}}{{{dataType}}}{{/isNullable}}{{/isModel}}{{^isModel}}{{{dataType}}}{{/isModel}} `{{#vendorExtensions.x-json-tag}}{{{.}}}{{/vendorExtensions.x-json-tag}}{{^vendorExtensions.x-json-tag}}json:"{{baseName}}{{^required}},omitempty{{/required}}"{{/vendorExtensions.x-json-tag}}{{#withXml}} xml:"{{baseName}}{{#isXmlAttribute}},attr{{/isXmlAttribute}}"{{/withXml}}{{#vendorExtensions.x-go-custom-tag}} {{{.}}}{{/vendorExtensions.x-go-custom-tag}}` {{/allVars}} } {{/isEnum}} diff --git a/schemas.yaml b/schemas.yaml index 7765a2245..88b4dec09 100644 --- a/schemas.yaml +++ b/schemas.yaml @@ -96,6 +96,10 @@ schemas: "$ref": schemas/translation_key.yaml#/translation_key translation_key_details: "$ref": schemas/translation_key_details.yaml#/translation_key_details + translation_key_linked_key: + "$ref": schemas/translation_key_linked_key.yaml#/translation_key_linked_key + translation_key_linked_key_parent: + "$ref": schemas/translation_key_linked_key_parent.yaml#/translation_key_linked_key_parent affected_resources: "$ref": schemas/affected_resources.yaml#/affected_resources translation_order: diff --git a/schemas/translation_key.yaml b/schemas/translation_key.yaml index fcd97c303..7f63cbcf5 100644 --- a/schemas/translation_key.yaml +++ b/schemas/translation_key.yaml @@ -28,41 +28,10 @@ translation_key: type: string format: date-time linked_key: - description: | - Describes this key's role in a parent–child link relationship. - Only present in the response when `include_linked_keys=true` is passed. - `null` when the key has no active link (either unlinked, or the parent - has been deleted). - type: object - properties: - role: - type: string - enum: - - parent - - child - description: > - Whether this key is the parent or the child in the link relationship. - parent: - description: > - The parent key's public identifier and name. Set for child keys; - `null` for parent keys. - type: object - properties: - id: - type: string - description: The parent key's public identifier (code). - example: "abc12345def67890abc12345def67890" - name: - type: string - description: The parent key's name. - example: "home.welcome.title" - children_count: - type: integer - nullable: true - description: > - The number of linked child keys. Set for parent keys; - `null` for child keys. - example: 3 + description: > + Only returned by the list and search endpoints when + `include_linked_keys=true` is passed. `null` means the key is not linked. + "$ref": "./translation_key_linked_key.yaml#/translation_key_linked_key" example: id: abcd1234cdef1234abcd1234cdef1234 name: home.index.headline diff --git a/schemas/translation_key_linked_key.yaml b/schemas/translation_key_linked_key.yaml new file mode 100644 index 000000000..b7da8e4f0 --- /dev/null +++ b/schemas/translation_key_linked_key.yaml @@ -0,0 +1,24 @@ +--- +translation_key_linked_key: + type: object + nullable: true + title: translation_key_linked_key + description: Describes a key's role in a parent–child link relationship. + properties: + role: + type: string + description: Whether this key is the parent or the child in the link relationship. + enum: + - parent + - child + parent: + "$ref": "./translation_key_linked_key_parent.yaml#/translation_key_linked_key_parent" + children_count: + type: integer + nullable: true + description: The number of linked child keys. Set for parent keys. + example: 3 + example: + role: parent + parent: + children_count: 3 diff --git a/schemas/translation_key_linked_key_parent.yaml b/schemas/translation_key_linked_key_parent.yaml new file mode 100644 index 000000000..ab2dba74c --- /dev/null +++ b/schemas/translation_key_linked_key_parent.yaml @@ -0,0 +1,15 @@ +--- +translation_key_linked_key_parent: + type: object + nullable: true + description: The parent key's public identifier and name. Set for child keys. + title: translation_key_linked_key_parent + properties: + id: + type: string + description: The parent key's public identifier (code). + example: abc12345def67890abc12345def67890 + name: + type: string + description: The parent key's name. + example: home.welcome.title