From e56c6a36abc3a34501417600668826917435901f Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:58:24 +0100 Subject: [PATCH 01/31] GO-4459: Add descriptions for swagger data models --- core/api/docs/docs.go | 207 ++++++++++++++++++++--- core/api/docs/swagger.json | 207 ++++++++++++++++++++--- core/api/docs/swagger.yaml | 172 ++++++++++++++++--- core/api/internal/auth/model.go | 6 +- core/api/internal/export/model.go | 4 +- core/api/internal/object/model.go | 112 ++++++------ core/api/internal/object/service_test.go | 9 +- core/api/internal/search/model.go | 10 +- core/api/internal/space/model.go | 56 +++--- core/api/pagination/model.go | 12 +- 10 files changed, 614 insertions(+), 181 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 838673118d..34e2a56f64 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -947,6 +947,7 @@ const docTemplate = `{ "type": "object", "properties": { "challenge_id": { + "description": "The challenge id associated with the displayed code and needed to solve the challenge for token", "type": "string", "example": "67647f5ecda913e9a2e11b26" } @@ -956,10 +957,12 @@ const docTemplate = `{ "type": "object", "properties": { "app_key": { + "description": "The permanent app key", "type": "string", "example": "zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=" }, "session_token": { + "description": "The ephemeral session token", "type": "string", "example": "eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII" } @@ -969,6 +972,7 @@ const docTemplate = `{ "type": "object", "properties": { "path": { + "description": "The path the object was exported to", "type": "string", "example": "/path/to/export" } @@ -978,6 +982,7 @@ const docTemplate = `{ "type": "object", "properties": { "align": { + "description": "The alignment of the block", "type": "string", "enum": [ "AlignLeft", @@ -988,10 +993,12 @@ const docTemplate = `{ "example": "AlignLeft" }, "background_color": { + "description": "The background color of the block", "type": "string", "example": "red" }, "children_ids": { + "description": "The ids of the block's children", "type": "array", "items": { "type": "string" @@ -1001,16 +1008,28 @@ const docTemplate = `{ ] }, "file": { - "$ref": "#/definitions/object.File" + "description": "The file of the block, if applicable", + "allOf": [ + { + "$ref": "#/definitions/object.File" + } + ] }, "id": { + "description": "The id of the block", "type": "string", "example": "64394517de52ad5acb89c66c" }, "text": { - "$ref": "#/definitions/object.Text" + "description": "The text of the block, if applicable", + "allOf": [ + { + "$ref": "#/definitions/object.Text" + } + ] }, "vertical_align": { + "description": "The vertical alignment of the block", "type": "string", "enum": [ "VerticalAlignTop", @@ -1025,30 +1044,37 @@ const docTemplate = `{ "type": "object", "properties": { "body": { + "description": "The body of the object", "type": "string", - "example": "Object Body" + "example": "This is the body of the object. Markdown syntax is supported here." }, "description": { + "description": "The description of the object", "type": "string", - "example": "Object Description" + "example": "This is a description of the object." }, "icon": { + "description": "The icon of the object", "type": "string", "example": "📄" }, "name": { + "description": "The name of the object", "type": "string", - "example": "Object Name" + "example": "My object" }, "object_type_unique_key": { + "description": "The unique key of the object type", "type": "string", "example": "ot-page" }, "source": { + "description": "The source url, only applicable for bookmarks", "type": "string", - "example": "https://source.com" + "example": "https://bookmark-source.com" }, "template_id": { + "description": "The id of the template to use", "type": "string", "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge" } @@ -1058,10 +1084,12 @@ const docTemplate = `{ "type": "object", "properties": { "details": { + "description": "The details", "type": "object", "additionalProperties": true }, "id": { + "description": "The id of the detail", "type": "string", "enum": [ "last_modified_date", @@ -1079,30 +1107,39 @@ const docTemplate = `{ "type": "object", "properties": { "added_at": { + "description": "The added at of the file", "type": "integer" }, "hash": { + "description": "The hash of the file", "type": "string" }, "mime": { + "description": "The mime of the file", "type": "string" }, "name": { + "description": "The name of the file", "type": "string" }, "size": { + "description": "The size of the file", "type": "integer" }, "state": { + "description": "The state of the file", "type": "string" }, "style": { + "description": "The style of the file", "type": "string" }, "target_object_id": { + "description": "The target object id of the file", "type": "string" }, "type": { + "description": "The type of the file", "type": "string" } } @@ -1111,46 +1148,56 @@ const docTemplate = `{ "type": "object", "properties": { "blocks": { + "description": "The blocks of the object", "type": "array", "items": { "$ref": "#/definitions/object.Block" } }, "details": { + "description": "The details of the object", "type": "array", "items": { "$ref": "#/definitions/object.Detail" } }, "icon": { + "description": "The icon of the object", "type": "string", "example": "📄" }, "id": { + "description": "The id of the object", "type": "string", "example": "bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ" }, "layout": { + "description": "The layout of the object", "type": "string", "example": "basic" }, "name": { + "description": "The name of the object", "type": "string", - "example": "Object Name" + "example": "My object" }, "root_id": { + "description": "The id of the object's root", "type": "string", "example": "bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u" }, "snippet": { + "description": "The snippet of the object, especially important for notes as they don't have a name", "type": "string", "example": "The beginning of the object body..." }, "space_id": { + "description": "The id of the space the object is in", "type": "string", "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1" }, "type": { + "description": "The type of the object", "type": "string", "example": "Page" } @@ -1160,7 +1207,12 @@ const docTemplate = `{ "type": "object", "properties": { "object": { - "$ref": "#/definitions/object.Object" + "description": "The object", + "allOf": [ + { + "$ref": "#/definitions/object.Object" + } + ] } } }, @@ -1168,18 +1220,22 @@ const docTemplate = `{ "type": "object", "properties": { "icon": { + "description": "The icon of the template", "type": "string", "example": "📄" }, "id": { + "description": "The id of the template", "type": "string", "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge" }, "name": { + "description": "The name of the template", "type": "string", - "example": "Template Name" + "example": "My template" }, "type": { + "description": "The type of the object", "type": "string", "example": "template" } @@ -1189,7 +1245,12 @@ const docTemplate = `{ "type": "object", "properties": { "template": { - "$ref": "#/definitions/object.Template" + "description": "The template", + "allOf": [ + { + "$ref": "#/definitions/object.Template" + } + ] } } }, @@ -1197,18 +1258,22 @@ const docTemplate = `{ "type": "object", "properties": { "checked": { + "description": "Whether the text is checked", "type": "boolean", "example": true }, "color": { + "description": "The color of the text", "type": "string", "example": "red" }, "icon": { + "description": "The icon of the text", "type": "string", "example": "📄" }, "style": { + "description": "The style of the text", "type": "string", "enum": [ "Paragraph", @@ -1229,8 +1294,9 @@ const docTemplate = `{ "example": "Paragraph" }, "text": { + "description": "The text", "type": "string", - "example": "Some text" + "example": "Some text..." } } }, @@ -1238,26 +1304,32 @@ const docTemplate = `{ "type": "object", "properties": { "icon": { + "description": "The icon of the type", "type": "string", "example": "📄" }, "id": { + "description": "The id of the type", "type": "string", "example": "bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu" }, "name": { + "description": "The name of the type", "type": "string", "example": "Page" }, "recommended_layout": { + "description": "The recommended layout of the type", "type": "string", "example": "todo" }, "type": { + "description": "The type of the object", "type": "string", "example": "type" }, "unique_key": { + "description": "The unique key of the type", "type": "string", "example": "ot-page" } @@ -1267,7 +1339,12 @@ const docTemplate = `{ "type": "object", "properties": { "type": { - "$ref": "#/definitions/object.Type" + "description": "The type", + "allOf": [ + { + "$ref": "#/definitions/object.Type" + } + ] } } }, @@ -1275,13 +1352,19 @@ const docTemplate = `{ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/object.Object" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1289,13 +1372,19 @@ const docTemplate = `{ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/object.Template" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1303,13 +1392,19 @@ const docTemplate = `{ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/object.Type" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1317,13 +1412,19 @@ const docTemplate = `{ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/space.Member" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1331,13 +1432,19 @@ const docTemplate = `{ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/space.Space" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1345,22 +1452,22 @@ const docTemplate = `{ "type": "object", "properties": { "has_more": { - "description": "whether there are more items available", + "description": "Indicates if there are more items available beyond the current result set", "type": "boolean", "example": true }, "limit": { - "description": "the current limit", + "description": "The maximum number of items returned in the result set", "type": "integer", "example": 100 }, "offset": { - "description": "the current offset", + "description": "The number of items skipped before starting to collect the result set", "type": "integer", "example": 0 }, "total": { - "description": "the total number of items available on that endpoint", + "description": "The total number of items available for the endpoint", "type": "integer", "example": 1024 } @@ -1370,16 +1477,30 @@ const docTemplate = `{ "type": "object", "properties": { "query": { - "type": "string" + "description": "The search term to look for in object names and snippets", + "type": "string", + "example": "test" }, "sort": { - "$ref": "#/definitions/search.SortOptions" + "description": "The sorting criteria and direction for the search results", + "allOf": [ + { + "$ref": "#/definitions/search.SortOptions" + } + ] }, "types": { + "description": "The types of objects to search for, specified by unique key or ID", "type": "array", "items": { "type": "string" - } + }, + "example": [ + "ot-note", + "ot-page", + "ot-678043f0cda9133be777049f", + "bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q" + ] } } }, @@ -1387,6 +1508,7 @@ const docTemplate = `{ "type": "object", "properties": { "direction": { + "description": "The direction to sort the search results", "type": "string", "default": "desc", "enum": [ @@ -1395,6 +1517,7 @@ const docTemplate = `{ ] }, "timestamp": { + "description": "The timestamp to sort the search results by", "type": "string", "default": "last_modified_date", "enum": [ @@ -1409,6 +1532,7 @@ const docTemplate = `{ "type": "object", "properties": { "name": { + "description": "The name of the space", "type": "string", "example": "New Space" } @@ -1418,7 +1542,12 @@ const docTemplate = `{ "type": "object", "properties": { "space": { - "$ref": "#/definitions/space.Space" + "description": "The created space", + "allOf": [ + { + "$ref": "#/definitions/space.Space" + } + ] } } }, @@ -1426,26 +1555,32 @@ const docTemplate = `{ "type": "object", "properties": { "global_name": { + "description": "The global name of the member in the network", "type": "string", "example": "john.any" }, "icon": { + "description": "The icon of the member", "type": "string", "example": "http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100" }, "id": { + "description": "The profile object id of the member", "type": "string", "example": "_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ" }, "identity": { + "description": "The identity of the member in the network", "type": "string", "example": "AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ" }, "name": { + "description": "The name of the member", "type": "string", "example": "John Doe" }, "role": { + "description": "The role of the member", "type": "string", "enum": [ "Reader", @@ -1456,6 +1591,7 @@ const docTemplate = `{ "example": "Owner" }, "type": { + "description": "The type of the object", "type": "string", "example": "member" } @@ -1465,78 +1601,97 @@ const docTemplate = `{ "type": "object", "properties": { "account_space_id": { + "description": "The id of the account space", "type": "string", "example": "bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1" }, "analytics_id": { + "description": "The analytics id of the account", "type": "string", "example": "624aecdd-4797-4611-9d61-a2ae5f53cf1c" }, "archive_object_id": { + "description": "The id of the archive object", "type": "string", "example": "bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri" }, "device_id": { + "description": "The id of the device", "type": "string", "example": "12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF" }, "gateway_url": { + "description": "The gateway url to serve files and media", "type": "string", "example": "http://127.0.0.1:31006" }, "home_object_id": { + "description": "The id of the home object", "type": "string", "example": "bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya" }, "icon": { + "description": "The icon of the space", "type": "string", "example": "http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay" }, "id": { + "description": "The id of the space", "type": "string", "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1" }, "local_storage_path": { + "description": "The local storage path of the account", "type": "string", "example": "/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha" }, "marketplace_workspace_id": { + "description": "The id of the marketplace workspace", "type": "string", "example": "_anytype_marketplace" }, "name": { + "description": "The name of the space", "type": "string", - "example": "Space Name" + "example": "My Space" }, "network_id": { + "description": "The network id of the space", "type": "string", "example": "N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU" }, "profile_object_id": { + "description": "The id of the profile object", "type": "string", "example": "bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4" }, "space_view_id": { + "description": "The id of the space view", "type": "string", "example": "bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy" }, "tech_space_id": { + "description": "The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself", "type": "string", "example": "bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1" }, "timezone": { + "description": "The timezone of the account", "type": "string", "example": "" }, "type": { + "description": "The type of the object", "type": "string", "example": "space" }, "widgets_id": { + "description": "The id of the widgets", "type": "string", "example": "bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva" }, "workspace_object_id": { + "description": "The id of the workspace object", "type": "string", "example": "bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y" } diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index cf8fe16d36..f5647435cd 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -941,6 +941,7 @@ "type": "object", "properties": { "challenge_id": { + "description": "The challenge id associated with the displayed code and needed to solve the challenge for token", "type": "string", "example": "67647f5ecda913e9a2e11b26" } @@ -950,10 +951,12 @@ "type": "object", "properties": { "app_key": { + "description": "The permanent app key", "type": "string", "example": "zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=" }, "session_token": { + "description": "The ephemeral session token", "type": "string", "example": "eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII" } @@ -963,6 +966,7 @@ "type": "object", "properties": { "path": { + "description": "The path the object was exported to", "type": "string", "example": "/path/to/export" } @@ -972,6 +976,7 @@ "type": "object", "properties": { "align": { + "description": "The alignment of the block", "type": "string", "enum": [ "AlignLeft", @@ -982,10 +987,12 @@ "example": "AlignLeft" }, "background_color": { + "description": "The background color of the block", "type": "string", "example": "red" }, "children_ids": { + "description": "The ids of the block's children", "type": "array", "items": { "type": "string" @@ -995,16 +1002,28 @@ ] }, "file": { - "$ref": "#/definitions/object.File" + "description": "The file of the block, if applicable", + "allOf": [ + { + "$ref": "#/definitions/object.File" + } + ] }, "id": { + "description": "The id of the block", "type": "string", "example": "64394517de52ad5acb89c66c" }, "text": { - "$ref": "#/definitions/object.Text" + "description": "The text of the block, if applicable", + "allOf": [ + { + "$ref": "#/definitions/object.Text" + } + ] }, "vertical_align": { + "description": "The vertical alignment of the block", "type": "string", "enum": [ "VerticalAlignTop", @@ -1019,30 +1038,37 @@ "type": "object", "properties": { "body": { + "description": "The body of the object", "type": "string", - "example": "Object Body" + "example": "This is the body of the object. Markdown syntax is supported here." }, "description": { + "description": "The description of the object", "type": "string", - "example": "Object Description" + "example": "This is a description of the object." }, "icon": { + "description": "The icon of the object", "type": "string", "example": "📄" }, "name": { + "description": "The name of the object", "type": "string", - "example": "Object Name" + "example": "My object" }, "object_type_unique_key": { + "description": "The unique key of the object type", "type": "string", "example": "ot-page" }, "source": { + "description": "The source url, only applicable for bookmarks", "type": "string", - "example": "https://source.com" + "example": "https://bookmark-source.com" }, "template_id": { + "description": "The id of the template to use", "type": "string", "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge" } @@ -1052,10 +1078,12 @@ "type": "object", "properties": { "details": { + "description": "The details", "type": "object", "additionalProperties": true }, "id": { + "description": "The id of the detail", "type": "string", "enum": [ "last_modified_date", @@ -1073,30 +1101,39 @@ "type": "object", "properties": { "added_at": { + "description": "The added at of the file", "type": "integer" }, "hash": { + "description": "The hash of the file", "type": "string" }, "mime": { + "description": "The mime of the file", "type": "string" }, "name": { + "description": "The name of the file", "type": "string" }, "size": { + "description": "The size of the file", "type": "integer" }, "state": { + "description": "The state of the file", "type": "string" }, "style": { + "description": "The style of the file", "type": "string" }, "target_object_id": { + "description": "The target object id of the file", "type": "string" }, "type": { + "description": "The type of the file", "type": "string" } } @@ -1105,46 +1142,56 @@ "type": "object", "properties": { "blocks": { + "description": "The blocks of the object", "type": "array", "items": { "$ref": "#/definitions/object.Block" } }, "details": { + "description": "The details of the object", "type": "array", "items": { "$ref": "#/definitions/object.Detail" } }, "icon": { + "description": "The icon of the object", "type": "string", "example": "📄" }, "id": { + "description": "The id of the object", "type": "string", "example": "bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ" }, "layout": { + "description": "The layout of the object", "type": "string", "example": "basic" }, "name": { + "description": "The name of the object", "type": "string", - "example": "Object Name" + "example": "My object" }, "root_id": { + "description": "The id of the object's root", "type": "string", "example": "bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u" }, "snippet": { + "description": "The snippet of the object, especially important for notes as they don't have a name", "type": "string", "example": "The beginning of the object body..." }, "space_id": { + "description": "The id of the space the object is in", "type": "string", "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1" }, "type": { + "description": "The type of the object", "type": "string", "example": "Page" } @@ -1154,7 +1201,12 @@ "type": "object", "properties": { "object": { - "$ref": "#/definitions/object.Object" + "description": "The object", + "allOf": [ + { + "$ref": "#/definitions/object.Object" + } + ] } } }, @@ -1162,18 +1214,22 @@ "type": "object", "properties": { "icon": { + "description": "The icon of the template", "type": "string", "example": "📄" }, "id": { + "description": "The id of the template", "type": "string", "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge" }, "name": { + "description": "The name of the template", "type": "string", - "example": "Template Name" + "example": "My template" }, "type": { + "description": "The type of the object", "type": "string", "example": "template" } @@ -1183,7 +1239,12 @@ "type": "object", "properties": { "template": { - "$ref": "#/definitions/object.Template" + "description": "The template", + "allOf": [ + { + "$ref": "#/definitions/object.Template" + } + ] } } }, @@ -1191,18 +1252,22 @@ "type": "object", "properties": { "checked": { + "description": "Whether the text is checked", "type": "boolean", "example": true }, "color": { + "description": "The color of the text", "type": "string", "example": "red" }, "icon": { + "description": "The icon of the text", "type": "string", "example": "📄" }, "style": { + "description": "The style of the text", "type": "string", "enum": [ "Paragraph", @@ -1223,8 +1288,9 @@ "example": "Paragraph" }, "text": { + "description": "The text", "type": "string", - "example": "Some text" + "example": "Some text..." } } }, @@ -1232,26 +1298,32 @@ "type": "object", "properties": { "icon": { + "description": "The icon of the type", "type": "string", "example": "📄" }, "id": { + "description": "The id of the type", "type": "string", "example": "bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu" }, "name": { + "description": "The name of the type", "type": "string", "example": "Page" }, "recommended_layout": { + "description": "The recommended layout of the type", "type": "string", "example": "todo" }, "type": { + "description": "The type of the object", "type": "string", "example": "type" }, "unique_key": { + "description": "The unique key of the type", "type": "string", "example": "ot-page" } @@ -1261,7 +1333,12 @@ "type": "object", "properties": { "type": { - "$ref": "#/definitions/object.Type" + "description": "The type", + "allOf": [ + { + "$ref": "#/definitions/object.Type" + } + ] } } }, @@ -1269,13 +1346,19 @@ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/object.Object" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1283,13 +1366,19 @@ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/object.Template" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1297,13 +1386,19 @@ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/object.Type" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1311,13 +1406,19 @@ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/space.Member" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1325,13 +1426,19 @@ "type": "object", "properties": { "data": { + "description": "The list of items in the current result set", "type": "array", "items": { "$ref": "#/definitions/space.Space" } }, "pagination": { - "$ref": "#/definitions/pagination.PaginationMeta" + "description": "The pagination metadata for the response", + "allOf": [ + { + "$ref": "#/definitions/pagination.PaginationMeta" + } + ] } } }, @@ -1339,22 +1446,22 @@ "type": "object", "properties": { "has_more": { - "description": "whether there are more items available", + "description": "Indicates if there are more items available beyond the current result set", "type": "boolean", "example": true }, "limit": { - "description": "the current limit", + "description": "The maximum number of items returned in the result set", "type": "integer", "example": 100 }, "offset": { - "description": "the current offset", + "description": "The number of items skipped before starting to collect the result set", "type": "integer", "example": 0 }, "total": { - "description": "the total number of items available on that endpoint", + "description": "The total number of items available for the endpoint", "type": "integer", "example": 1024 } @@ -1364,16 +1471,30 @@ "type": "object", "properties": { "query": { - "type": "string" + "description": "The search term to look for in object names and snippets", + "type": "string", + "example": "test" }, "sort": { - "$ref": "#/definitions/search.SortOptions" + "description": "The sorting criteria and direction for the search results", + "allOf": [ + { + "$ref": "#/definitions/search.SortOptions" + } + ] }, "types": { + "description": "The types of objects to search for, specified by unique key or ID", "type": "array", "items": { "type": "string" - } + }, + "example": [ + "ot-note", + "ot-page", + "ot-678043f0cda9133be777049f", + "bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q" + ] } } }, @@ -1381,6 +1502,7 @@ "type": "object", "properties": { "direction": { + "description": "The direction to sort the search results", "type": "string", "default": "desc", "enum": [ @@ -1389,6 +1511,7 @@ ] }, "timestamp": { + "description": "The timestamp to sort the search results by", "type": "string", "default": "last_modified_date", "enum": [ @@ -1403,6 +1526,7 @@ "type": "object", "properties": { "name": { + "description": "The name of the space", "type": "string", "example": "New Space" } @@ -1412,7 +1536,12 @@ "type": "object", "properties": { "space": { - "$ref": "#/definitions/space.Space" + "description": "The created space", + "allOf": [ + { + "$ref": "#/definitions/space.Space" + } + ] } } }, @@ -1420,26 +1549,32 @@ "type": "object", "properties": { "global_name": { + "description": "The global name of the member in the network", "type": "string", "example": "john.any" }, "icon": { + "description": "The icon of the member", "type": "string", "example": "http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100" }, "id": { + "description": "The profile object id of the member", "type": "string", "example": "_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ" }, "identity": { + "description": "The identity of the member in the network", "type": "string", "example": "AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ" }, "name": { + "description": "The name of the member", "type": "string", "example": "John Doe" }, "role": { + "description": "The role of the member", "type": "string", "enum": [ "Reader", @@ -1450,6 +1585,7 @@ "example": "Owner" }, "type": { + "description": "The type of the object", "type": "string", "example": "member" } @@ -1459,78 +1595,97 @@ "type": "object", "properties": { "account_space_id": { + "description": "The id of the account space", "type": "string", "example": "bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1" }, "analytics_id": { + "description": "The analytics id of the account", "type": "string", "example": "624aecdd-4797-4611-9d61-a2ae5f53cf1c" }, "archive_object_id": { + "description": "The id of the archive object", "type": "string", "example": "bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri" }, "device_id": { + "description": "The id of the device", "type": "string", "example": "12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF" }, "gateway_url": { + "description": "The gateway url to serve files and media", "type": "string", "example": "http://127.0.0.1:31006" }, "home_object_id": { + "description": "The id of the home object", "type": "string", "example": "bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya" }, "icon": { + "description": "The icon of the space", "type": "string", "example": "http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay" }, "id": { + "description": "The id of the space", "type": "string", "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1" }, "local_storage_path": { + "description": "The local storage path of the account", "type": "string", "example": "/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha" }, "marketplace_workspace_id": { + "description": "The id of the marketplace workspace", "type": "string", "example": "_anytype_marketplace" }, "name": { + "description": "The name of the space", "type": "string", - "example": "Space Name" + "example": "My Space" }, "network_id": { + "description": "The network id of the space", "type": "string", "example": "N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU" }, "profile_object_id": { + "description": "The id of the profile object", "type": "string", "example": "bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4" }, "space_view_id": { + "description": "The id of the space view", "type": "string", "example": "bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy" }, "tech_space_id": { + "description": "The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself", "type": "string", "example": "bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1" }, "timezone": { + "description": "The timezone of the account", "type": "string", "example": "" }, "type": { + "description": "The type of the object", "type": "string", "example": "space" }, "widgets_id": { + "description": "The id of the widgets", "type": "string", "example": "bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva" }, "workspace_object_id": { + "description": "The id of the workspace object", "type": "string", "example": "bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y" } diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 550a59d1c6..c9ba287575 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -3,27 +3,33 @@ definitions: auth.DisplayCodeResponse: properties: challenge_id: + description: The challenge id associated with the displayed code and needed + to solve the challenge for token example: 67647f5ecda913e9a2e11b26 type: string type: object auth.TokenResponse: properties: app_key: + description: The permanent app key example: zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6= type: string session_token: + description: The ephemeral session token example: eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII type: string type: object export.ObjectExportResponse: properties: path: + description: The path the object was exported to example: /path/to/export type: string type: object object.Block: properties: align: + description: The alignment of the block enum: - AlignLeft - AlignCenter @@ -32,22 +38,30 @@ definitions: example: AlignLeft type: string background_color: + description: The background color of the block example: red type: string children_ids: + description: The ids of the block's children example: - '[''6797ce8ecda913cde14b02dc'']' items: type: string type: array file: - $ref: '#/definitions/object.File' + allOf: + - $ref: '#/definitions/object.File' + description: The file of the block, if applicable id: + description: The id of the block example: 64394517de52ad5acb89c66c type: string text: - $ref: '#/definitions/object.Text' + allOf: + - $ref: '#/definitions/object.Text' + description: The text of the block, if applicable vertical_align: + description: The vertical alignment of the block enum: - VerticalAlignTop - VerticalAlignMiddle @@ -58,24 +72,31 @@ definitions: object.CreateObjectRequest: properties: body: - example: Object Body + description: The body of the object + example: This is the body of the object. Markdown syntax is supported here. type: string description: - example: Object Description + description: The description of the object + example: This is a description of the object. type: string icon: + description: The icon of the object example: "\U0001F4C4" type: string name: - example: Object Name + description: The name of the object + example: My object type: string object_type_unique_key: + description: The unique key of the object type example: ot-page type: string source: - example: https://source.com + description: The source url, only applicable for bookmarks + example: https://bookmark-source.com type: string template_id: + description: The id of the template to use example: bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge type: string type: object @@ -83,8 +104,10 @@ definitions: properties: details: additionalProperties: true + description: The details type: object id: + description: The id of the detail enum: - last_modified_date - last_modified_by @@ -98,96 +121,128 @@ definitions: object.File: properties: added_at: + description: The added at of the file type: integer hash: + description: The hash of the file type: string mime: + description: The mime of the file type: string name: + description: The name of the file type: string size: + description: The size of the file type: integer state: + description: The state of the file type: string style: + description: The style of the file type: string target_object_id: + description: The target object id of the file type: string type: + description: The type of the file type: string type: object object.Object: properties: blocks: + description: The blocks of the object items: $ref: '#/definitions/object.Block' type: array details: + description: The details of the object items: $ref: '#/definitions/object.Detail' type: array icon: + description: The icon of the object example: "\U0001F4C4" type: string id: + description: The id of the object example: bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ type: string layout: + description: The layout of the object example: basic type: string name: - example: Object Name + description: The name of the object + example: My object type: string root_id: + description: The id of the object's root example: bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u type: string snippet: + description: The snippet of the object, especially important for notes as + they don't have a name example: The beginning of the object body... type: string space_id: + description: The id of the space the object is in example: bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1 type: string type: + description: The type of the object example: Page type: string type: object object.ObjectResponse: properties: object: - $ref: '#/definitions/object.Object' + allOf: + - $ref: '#/definitions/object.Object' + description: The object type: object object.Template: properties: icon: + description: The icon of the template example: "\U0001F4C4" type: string id: + description: The id of the template example: bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge type: string name: - example: Template Name + description: The name of the template + example: My template type: string type: + description: The type of the object example: template type: string type: object object.TemplateResponse: properties: template: - $ref: '#/definitions/object.Template' + allOf: + - $ref: '#/definitions/object.Template' + description: The template type: object object.Text: properties: checked: + description: Whether the text is checked example: true type: boolean color: + description: The color of the text example: red type: string icon: + description: The icon of the text example: "\U0001F4C4" type: string style: + description: The style of the text enum: - Paragraph - Header1 @@ -206,106 +261,143 @@ definitions: example: Paragraph type: string text: - example: Some text + description: The text + example: Some text... type: string type: object object.Type: properties: icon: + description: The icon of the type example: "\U0001F4C4" type: string id: + description: The id of the type example: bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu type: string name: + description: The name of the type example: Page type: string recommended_layout: + description: The recommended layout of the type example: todo type: string type: + description: The type of the object example: type type: string unique_key: + description: The unique key of the type example: ot-page type: string type: object object.TypeResponse: properties: type: - $ref: '#/definitions/object.Type' + allOf: + - $ref: '#/definitions/object.Type' + description: The type type: object pagination.PaginatedResponse-object_Object: properties: data: + description: The list of items in the current result set items: $ref: '#/definitions/object.Object' type: array pagination: - $ref: '#/definitions/pagination.PaginationMeta' + allOf: + - $ref: '#/definitions/pagination.PaginationMeta' + description: The pagination metadata for the response type: object pagination.PaginatedResponse-object_Template: properties: data: + description: The list of items in the current result set items: $ref: '#/definitions/object.Template' type: array pagination: - $ref: '#/definitions/pagination.PaginationMeta' + allOf: + - $ref: '#/definitions/pagination.PaginationMeta' + description: The pagination metadata for the response type: object pagination.PaginatedResponse-object_Type: properties: data: + description: The list of items in the current result set items: $ref: '#/definitions/object.Type' type: array pagination: - $ref: '#/definitions/pagination.PaginationMeta' + allOf: + - $ref: '#/definitions/pagination.PaginationMeta' + description: The pagination metadata for the response type: object pagination.PaginatedResponse-space_Member: properties: data: + description: The list of items in the current result set items: $ref: '#/definitions/space.Member' type: array pagination: - $ref: '#/definitions/pagination.PaginationMeta' + allOf: + - $ref: '#/definitions/pagination.PaginationMeta' + description: The pagination metadata for the response type: object pagination.PaginatedResponse-space_Space: properties: data: + description: The list of items in the current result set items: $ref: '#/definitions/space.Space' type: array pagination: - $ref: '#/definitions/pagination.PaginationMeta' + allOf: + - $ref: '#/definitions/pagination.PaginationMeta' + description: The pagination metadata for the response type: object pagination.PaginationMeta: properties: has_more: - description: whether there are more items available + description: Indicates if there are more items available beyond the current + result set example: true type: boolean limit: - description: the current limit + description: The maximum number of items returned in the result set example: 100 type: integer offset: - description: the current offset + description: The number of items skipped before starting to collect the result + set example: 0 type: integer total: - description: the total number of items available on that endpoint + description: The total number of items available for the endpoint example: 1024 type: integer type: object search.SearchRequest: properties: query: + description: The search term to look for in object names and snippets + example: test type: string sort: - $ref: '#/definitions/search.SortOptions' + allOf: + - $ref: '#/definitions/search.SortOptions' + description: The sorting criteria and direction for the search results types: + description: The types of objects to search for, specified by unique key or + ID + example: + - ot-note + - ot-page + - ot-678043f0cda9133be777049f + - bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q items: type: string type: array @@ -314,12 +406,14 @@ definitions: properties: direction: default: desc + description: The direction to sort the search results enum: - asc - desc type: string timestamp: default: last_modified_date + description: The timestamp to sort the search results by enum: - created_date - last_modified_date @@ -329,32 +423,41 @@ definitions: space.CreateSpaceRequest: properties: name: + description: The name of the space example: New Space type: string type: object space.CreateSpaceResponse: properties: space: - $ref: '#/definitions/space.Space' + allOf: + - $ref: '#/definitions/space.Space' + description: The created space type: object space.Member: properties: global_name: + description: The global name of the member in the network example: john.any type: string icon: + description: The icon of the member example: http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100 type: string id: + description: The profile object id of the member example: _participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ type: string identity: + description: The identity of the member in the network example: AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ type: string name: + description: The name of the member example: John Doe type: string role: + description: The role of the member enum: - Reader - Writer @@ -363,66 +466,87 @@ definitions: example: Owner type: string type: + description: The type of the object example: member type: string type: object space.Space: properties: account_space_id: + description: The id of the account space example: bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1 type: string analytics_id: + description: The analytics id of the account example: 624aecdd-4797-4611-9d61-a2ae5f53cf1c type: string archive_object_id: + description: The id of the archive object example: bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri type: string device_id: + description: The id of the device example: 12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF type: string gateway_url: + description: The gateway url to serve files and media example: http://127.0.0.1:31006 type: string home_object_id: + description: The id of the home object example: bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya type: string icon: + description: The icon of the space example: http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay type: string id: + description: The id of the space example: bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1 type: string local_storage_path: + description: The local storage path of the account example: /Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha type: string marketplace_workspace_id: + description: The id of the marketplace workspace example: _anytype_marketplace type: string name: - example: Space Name + description: The name of the space + example: My Space type: string network_id: + description: The network id of the space example: N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU type: string profile_object_id: + description: The id of the profile object example: bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4 type: string space_view_id: + description: The id of the space view example: bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy type: string tech_space_id: + description: The id of tech space, where objects outside of user's actual + spaces are stored, e.g. spaces itself example: bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1 type: string timezone: + description: The timezone of the account example: "" type: string type: + description: The type of the object example: space type: string widgets_id: + description: The id of the widgets example: bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva type: string workspace_object_id: + description: The id of the workspace object example: bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y type: string type: object diff --git a/core/api/internal/auth/model.go b/core/api/internal/auth/model.go index 2d34926f56..221797cd36 100644 --- a/core/api/internal/auth/model.go +++ b/core/api/internal/auth/model.go @@ -1,10 +1,10 @@ package auth type DisplayCodeResponse struct { - ChallengeId string `json:"challenge_id" example:"67647f5ecda913e9a2e11b26"` + ChallengeId string `json:"challenge_id" example:"67647f5ecda913e9a2e11b26"` // The challenge id associated with the displayed code and needed to solve the challenge for token } type TokenResponse struct { - SessionToken string `json:"session_token" example:"eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII"` - AppKey string `json:"app_key" example:"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6="` + SessionToken string `json:"session_token" example:"eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII"` // The ephemeral session token + AppKey string `json:"app_key" example:"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6="` // The permanent app key } diff --git a/core/api/internal/export/model.go b/core/api/internal/export/model.go index dde2422462..e6541b62bc 100644 --- a/core/api/internal/export/model.go +++ b/core/api/internal/export/model.go @@ -1,9 +1,9 @@ package export type ObjectExportRequest struct { - Path string `json:"path" example:"/path/to/export"` + Path string `json:"path" example:"/path/to/export"` // The path to export the object to } type ObjectExportResponse struct { - Path string `json:"path" example:"/path/to/export"` + Path string `json:"path" example:"/path/to/export"` // The path the object was exported to } diff --git a/core/api/internal/object/model.go b/core/api/internal/object/model.go index 70ba449aa0..d591214913 100644 --- a/core/api/internal/object/model.go +++ b/core/api/internal/object/model.go @@ -1,93 +1,93 @@ package object type CreateObjectRequest struct { - Name string `json:"name" example:"Object Name"` - Icon string `json:"icon" example:"📄"` - Description string `json:"description" example:"Object Description"` - Body string `json:"body" example:"Object Body"` - Source string `json:"source" example:"https://source.com"` - TemplateId string `json:"template_id" example:"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge"` - ObjectTypeUniqueKey string `json:"object_type_unique_key" example:"ot-page"` + Name string `json:"name" example:"My object"` // The name of the object + Icon string `json:"icon" example:"📄"` // The icon of the object + Description string `json:"description" example:"This is a description of the object."` // The description of the object + Body string `json:"body" example:"This is the body of the object. Markdown syntax is supported here."` // The body of the object + Source string `json:"source" example:"https://bookmark-source.com"` // The source url, only applicable for bookmarks + TemplateId string `json:"template_id" example:"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge"` // The id of the template to use + ObjectTypeUniqueKey string `json:"object_type_unique_key" example:"ot-page"` // The unique key of the object type } type ObjectResponse struct { - Object Object `json:"object"` + Object Object `json:"object"` // The object } type Object struct { - Type string `json:"type" example:"Page"` - Id string `json:"id" example:"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ"` - Name string `json:"name" example:"Object Name"` - Icon string `json:"icon" example:"📄"` - Snippet string `json:"snippet" example:"The beginning of the object body..."` - Layout string `json:"layout" example:"basic"` - SpaceId string `json:"space_id" example:"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1"` - RootId string `json:"root_id" example:"bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u"` - Blocks []Block `json:"blocks"` - Details []Detail `json:"details"` + Type string `json:"type" example:"Page"` // The type of the object + Id string `json:"id" example:"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ"` // The id of the object + Name string `json:"name" example:"My object"` // The name of the object + Icon string `json:"icon" example:"📄"` // The icon of the object + Snippet string `json:"snippet" example:"The beginning of the object body..."` // The snippet of the object, especially important for notes as they don't have a name + Layout string `json:"layout" example:"basic"` // The layout of the object + SpaceId string `json:"space_id" example:"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1"` // The id of the space the object is in + RootId string `json:"root_id" example:"bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u"` // The id of the object's root + Blocks []Block `json:"blocks"` // The blocks of the object + Details []Detail `json:"details"` // The details of the object } type Block struct { - Id string `json:"id" example:"64394517de52ad5acb89c66c"` - ChildrenIds []string `json:"children_ids" example:"['6797ce8ecda913cde14b02dc']"` - BackgroundColor string `json:"background_color" example:"red"` - Align string `json:"align" enums:"AlignLeft,AlignCenter,AlignRight,AlignJustify" example:"AlignLeft"` - VerticalAlign string `json:"vertical_align" enums:"VerticalAlignTop,VerticalAlignMiddle,VerticalAlignBottom" example:"VerticalAlignTop"` - Text *Text `json:"text,omitempty"` - File *File `json:"file,omitempty"` + Id string `json:"id" example:"64394517de52ad5acb89c66c"` // The id of the block + ChildrenIds []string `json:"children_ids" example:"['6797ce8ecda913cde14b02dc']"` // The ids of the block's children + BackgroundColor string `json:"background_color" example:"red"` // The background color of the block + Align string `json:"align" enums:"AlignLeft,AlignCenter,AlignRight,AlignJustify" example:"AlignLeft"` // The alignment of the block + VerticalAlign string `json:"vertical_align" enums:"VerticalAlignTop,VerticalAlignMiddle,VerticalAlignBottom" example:"VerticalAlignTop"` // The vertical alignment of the block + Text *Text `json:"text,omitempty"` // The text of the block, if applicable + File *File `json:"file,omitempty"` // The file of the block, if applicable } type Text struct { - Text string `json:"text" example:"Some text"` - Style string `json:"style" enums:"Paragraph,Header1,Header2,Header3,Header4,Quote,Code,Title,Checkbox,Marked,Numbered,Toggle,Description,Callout" example:"Paragraph"` - Checked bool `json:"checked" example:"true"` - Color string `json:"color" example:"red"` - Icon string `json:"icon" example:"📄"` + Text string `json:"text" example:"Some text..."` // The text + Style string `json:"style" enums:"Paragraph,Header1,Header2,Header3,Header4,Quote,Code,Title,Checkbox,Marked,Numbered,Toggle,Description,Callout" example:"Paragraph"` // The style of the text + Checked bool `json:"checked" example:"true"` // Whether the text is checked + Color string `json:"color" example:"red"` // The color of the text + Icon string `json:"icon" example:"📄"` // The icon of the text } type File struct { - Hash string `json:"hash"` - Name string `json:"name"` - Type string `json:"type"` - Mime string `json:"mime"` - Size int `json:"size"` - AddedAt int `json:"added_at"` - TargetObjectId string `json:"target_object_id"` - State string `json:"state"` - Style string `json:"style"` + Hash string `json:"hash"` // The hash of the file + Name string `json:"name"` // The name of the file + Type string `json:"type"` // The type of the file + Mime string `json:"mime"` // The mime of the file + Size int `json:"size"` // The size of the file + AddedAt int `json:"added_at"` // The added at of the file + TargetObjectId string `json:"target_object_id"` // The target object id of the file + State string `json:"state"` // The state of the file + Style string `json:"style"` // The style of the file } type Detail struct { - Id string `json:"id" enums:"last_modified_date,last_modified_by,created_date,created_by,last_opened_date,tags" example:"last_modified_date"` - Details map[string]interface{} `json:"details"` + Id string `json:"id" enums:"last_modified_date,last_modified_by,created_date,created_by,last_opened_date,tags" example:"last_modified_date"` // The id of the detail + Details map[string]interface{} `json:"details"` // The details } type Tag struct { - Id string `json:"id" example:"bafyreiaixlnaefu3ci22zdenjhsdlyaeeoyjrsid5qhfeejzlccijbj7sq"` - Name string `json:"name" example:"Tag Name"` - Color string `json:"color" example:"yellow"` + Id string `json:"id" example:"bafyreiaixlnaefu3ci22zdenjhsdlyaeeoyjrsid5qhfeejzlccijbj7sq"` // The id of the tag + Name string `json:"name" example:"in-progress"` // The name of the tag + Color string `json:"color" example:"yellow"` // The color of the tag } type TypeResponse struct { - Type Type `json:"type"` + Type Type `json:"type"` // The type } type Type struct { - Type string `json:"type" example:"type"` - Id string `json:"id" example:"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu"` - UniqueKey string `json:"unique_key" example:"ot-page"` - Name string `json:"name" example:"Page"` - Icon string `json:"icon" example:"📄"` - RecommendedLayout string `json:"recommended_layout" example:"todo"` + Type string `json:"type" example:"type"` // The type of the object + Id string `json:"id" example:"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu"` // The id of the type + UniqueKey string `json:"unique_key" example:"ot-page"` // The unique key of the type + Name string `json:"name" example:"Page"` // The name of the type + Icon string `json:"icon" example:"📄"` // The icon of the type + RecommendedLayout string `json:"recommended_layout" example:"todo"` // The recommended layout of the type } type TemplateResponse struct { - Template Template `json:"template"` + Template Template `json:"template"` // The template } type Template struct { - Type string `json:"type" example:"template"` - Id string `json:"id" example:"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge"` - Name string `json:"name" example:"Template Name"` - Icon string `json:"icon" example:"📄"` + Type string `json:"type" example:"template"` // The type of the object + Id string `json:"id" example:"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge"` // The id of the template + Name string `json:"name" example:"My template"` // The name of the template + Icon string `json:"icon" example:"📄"` // The icon of the template } diff --git a/core/api/internal/object/service_test.go b/core/api/internal/object/service_test.go index 10ba7e1c4d..5ae1f6ba25 100644 --- a/core/api/internal/object/service_test.go +++ b/core/api/internal/object/service_test.go @@ -390,7 +390,7 @@ func TestObjectService_CreateObject(t *testing.T) { bundle.RelationKeyOrigin.String(): pbtypes.Int64(int64(model.ObjectOrigin_api)), }, }, - TemplateId: "", + TemplateId: mockedTemplateId, SpaceId: mockedSpaceId, ObjectTypeUniqueKey: mockedObjectTypeUniqueKey, WithChat: false, @@ -483,10 +483,9 @@ func TestObjectService_CreateObject(t *testing.T) { // when object, err := fx.CreateObject(ctx, mockedSpaceId, CreateObjectRequest{ - Name: mockedObjectName, - Icon: mockedObjectIcon, - // TODO: use actual values - TemplateId: "", + Name: mockedObjectName, + Icon: mockedObjectIcon, + TemplateId: mockedTemplateId, ObjectTypeUniqueKey: mockedObjectTypeUniqueKey, }) diff --git a/core/api/internal/search/model.go b/core/api/internal/search/model.go index f52cf59e42..1709338418 100644 --- a/core/api/internal/search/model.go +++ b/core/api/internal/search/model.go @@ -1,12 +1,12 @@ package search type SearchRequest struct { - Query string `json:"query"` - Types []string `json:"types"` - Sort SortOptions `json:"sort"` + Query string `json:"query" example:"test"` // The search term to look for in object names and snippets + Types []string `json:"types" example:"ot-note,ot-page,ot-678043f0cda9133be777049f,bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q"` // The types of objects to search for, specified by unique key or ID + Sort SortOptions `json:"sort"` // The sorting criteria and direction for the search results } type SortOptions struct { - Direction string `json:"direction" enums:"asc,desc" default:"desc"` - Timestamp string `json:"timestamp" enums:"created_date,last_modified_date,last_opened_date" default:"last_modified_date"` + Direction string `json:"direction" enums:"asc,desc" default:"desc"` // The direction to sort the search results + Timestamp string `json:"timestamp" enums:"created_date,last_modified_date,last_opened_date" default:"last_modified_date"` // The timestamp to sort the search results by } diff --git a/core/api/internal/space/model.go b/core/api/internal/space/model.go index d13951c3f5..73cbe732be 100644 --- a/core/api/internal/space/model.go +++ b/core/api/internal/space/model.go @@ -1,41 +1,41 @@ package space type CreateSpaceRequest struct { - Name string `json:"name" example:"New Space"` + Name string `json:"name" example:"New Space"` // The name of the space } type CreateSpaceResponse struct { - Space Space `json:"space"` + Space Space `json:"space"` // The created space } type Space struct { - Type string `json:"type" example:"space"` - Id string `json:"id" example:"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1"` - Name string `json:"name" example:"Space Name"` - Icon string `json:"icon" example:"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay"` - HomeObjectId string `json:"home_object_id" example:"bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya"` - ArchiveObjectId string `json:"archive_object_id" example:"bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri"` - ProfileObjectId string `json:"profile_object_id" example:"bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4"` - MarketplaceWorkspaceId string `json:"marketplace_workspace_id" example:"_anytype_marketplace"` - WorkspaceObjectId string `json:"workspace_object_id" example:"bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y"` - DeviceId string `json:"device_id" example:"12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF"` - AccountSpaceId string `json:"account_space_id" example:"bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1"` - WidgetsId string `json:"widgets_id" example:"bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva"` - SpaceViewId string `json:"space_view_id" example:"bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy"` - TechSpaceId string `json:"tech_space_id" example:"bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1"` - GatewayUrl string `json:"gateway_url" example:"http://127.0.0.1:31006"` - LocalStoragePath string `json:"local_storage_path" example:"/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha"` - Timezone string `json:"timezone" example:""` - AnalyticsId string `json:"analytics_id" example:"624aecdd-4797-4611-9d61-a2ae5f53cf1c"` - NetworkId string `json:"network_id" example:"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU"` + Type string `json:"type" example:"space"` // The type of the object + Id string `json:"id" example:"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1"` // The id of the space + Name string `json:"name" example:"My Space"` // The name of the space + Icon string `json:"icon" example:"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay"` // The icon of the space + HomeObjectId string `json:"home_object_id" example:"bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya"` // The id of the home object + ArchiveObjectId string `json:"archive_object_id" example:"bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri"` // The id of the archive object + ProfileObjectId string `json:"profile_object_id" example:"bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4"` // The id of the profile object + MarketplaceWorkspaceId string `json:"marketplace_workspace_id" example:"_anytype_marketplace"` // The id of the marketplace workspace + WorkspaceObjectId string `json:"workspace_object_id" example:"bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y"` // The id of the workspace object + DeviceId string `json:"device_id" example:"12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF"` // The id of the device + AccountSpaceId string `json:"account_space_id" example:"bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1"` // The id of the account space + WidgetsId string `json:"widgets_id" example:"bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva"` // The id of the widgets + SpaceViewId string `json:"space_view_id" example:"bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy"` // The id of the space view + TechSpaceId string `json:"tech_space_id" example:"bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1"` // The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself + GatewayUrl string `json:"gateway_url" example:"http://127.0.0.1:31006"` // The gateway url to serve files and media + LocalStoragePath string `json:"local_storage_path" example:"/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha"` // The local storage path of the account + Timezone string `json:"timezone" example:""` // The timezone of the account + AnalyticsId string `json:"analytics_id" example:"624aecdd-4797-4611-9d61-a2ae5f53cf1c"` // The analytics id of the account + NetworkId string `json:"network_id" example:"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU"` // The network id of the space } type Member struct { - Type string `json:"type" example:"member"` - Id string `json:"id" example:"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ"` - Name string `json:"name" example:"John Doe"` - Icon string `json:"icon" example:"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100"` - Identity string `json:"identity" example:"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ"` - GlobalName string `json:"global_name" example:"john.any"` - Role string `json:"role" enums:"Reader,Writer,Owner,NoPermission" example:"Owner"` + Type string `json:"type" example:"member"` // The type of the object + Id string `json:"id" example:"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ"` // The profile object id of the member + Name string `json:"name" example:"John Doe"` // The name of the member + Icon string `json:"icon" example:"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100"` // The icon of the member + Identity string `json:"identity" example:"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ"` // The identity of the member in the network + GlobalName string `json:"global_name" example:"john.any"` // The global name of the member in the network + Role string `json:"role" enums:"Reader,Writer,Owner,NoPermission" example:"Owner"` // The role of the member } diff --git a/core/api/pagination/model.go b/core/api/pagination/model.go index 06539ce635..3d679fec48 100644 --- a/core/api/pagination/model.go +++ b/core/api/pagination/model.go @@ -1,13 +1,13 @@ package pagination type PaginationMeta struct { - Total int `json:"total" example:"1024"` // the total number of items available on that endpoint - Offset int `json:"offset" example:"0"` // the current offset - Limit int `json:"limit" example:"100"` // the current limit - HasMore bool `json:"has_more" example:"true"` // whether there are more items available + Total int `json:"total" example:"1024"` // The total number of items available for the endpoint + Offset int `json:"offset" example:"0"` // The number of items skipped before starting to collect the result set + Limit int `json:"limit" example:"100"` // The maximum number of items returned in the result set + HasMore bool `json:"has_more" example:"true"` // Indicates if there are more items available beyond the current result set } type PaginatedResponse[T any] struct { - Data []T `json:"data"` - Pagination PaginationMeta `json:"pagination"` + Data []T `json:"data"` // The list of items in the current result set + Pagination PaginationMeta `json:"pagination"` // The pagination metadata for the response } From c7acd87e2b90c48e49caa24ee2fdee1104367a30 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:08:08 +0100 Subject: [PATCH 02/31] GO-4459: Add swagger examples for errors --- core/api/docs/docs.go | 15 ++++++++----- core/api/docs/swagger.json | 15 ++++++++----- core/api/docs/swagger.yaml | 5 +++++ core/api/util/error.go | 46 +++++++++++++++++++++++--------------- 4 files changed, 53 insertions(+), 28 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 34e2a56f64..239cbb9d84 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -1704,7 +1704,8 @@ const docTemplate = `{ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Forbidden" } } } @@ -1717,7 +1718,8 @@ const docTemplate = `{ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Resource not found" } } } @@ -1730,7 +1732,8 @@ const docTemplate = `{ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Internal server error" } } } @@ -1743,7 +1746,8 @@ const docTemplate = `{ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Unauthorized" } } } @@ -1756,7 +1760,8 @@ const docTemplate = `{ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Bad request" } } } diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index f5647435cd..72c7919b2c 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -1698,7 +1698,8 @@ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Forbidden" } } } @@ -1711,7 +1712,8 @@ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Resource not found" } } } @@ -1724,7 +1726,8 @@ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Internal server error" } } } @@ -1737,7 +1740,8 @@ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Unauthorized" } } } @@ -1750,7 +1754,8 @@ "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "example": "Bad request" } } } diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index c9ba287575..fbbc53a88e 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -555,6 +555,7 @@ definitions: error: properties: message: + example: Forbidden type: string type: object type: object @@ -563,6 +564,7 @@ definitions: error: properties: message: + example: Resource not found type: string type: object type: object @@ -571,6 +573,7 @@ definitions: error: properties: message: + example: Internal server error type: string type: object type: object @@ -579,6 +582,7 @@ definitions: error: properties: message: + example: Unauthorized type: string type: object type: object @@ -587,6 +591,7 @@ definitions: error: properties: message: + example: Bad request type: string type: object type: object diff --git a/core/api/util/error.go b/core/api/util/error.go index b7553f3fd2..acec46041c 100644 --- a/core/api/util/error.go +++ b/core/api/util/error.go @@ -5,38 +5,38 @@ import ( "net/http" ) -// 400 +// ValidationError is a struct for 400 errors type ValidationError struct { Error struct { - Message string `json:"message"` + Message string `json:"message" example:"Bad request"` } `json:"error"` } -// 401 +// UnauthorizedError is a struct for 401 errors type UnauthorizedError struct { Error struct { - Message string `json:"message"` + Message string `json:"message" example:"Unauthorized"` } `json:"error"` } -// 403 +// ForbiddenError is a struct for 403 errors type ForbiddenError struct { Error struct { - Message string `json:"message"` + Message string `json:"message" example:"Forbidden"` } `json:"error"` } -// 404 +// NotFoundError is a struct for 404 errors type NotFoundError struct { Error struct { - Message string `json:"message"` + Message string `json:"message" example:"Resource not found"` } `json:"error"` } -// 500 +// ServerError is a struct for 500 errors type ServerError struct { Error struct { - Message string `json:"message"` + Message string `json:"message" example:"Internal server error"` } `json:"error"` } @@ -72,10 +72,11 @@ func MapErrorCode(err error, mappings ...errCodeMapping) int { // for the given HTTP code, embedding the supplied message. func CodeToAPIError(code int, message string) any { switch code { - case http.StatusNotFound: - return NotFoundError{ + + case http.StatusBadRequest: + return ValidationError{ Error: struct { - Message string `json:"message"` + Message string `json:"message" example:"Bad request"` }{ Message: message, }, @@ -84,16 +85,25 @@ func CodeToAPIError(code int, message string) any { case http.StatusUnauthorized: return UnauthorizedError{ Error: struct { - Message string `json:"message"` + Message string `json:"message" example:"Unauthorized"` }{ Message: message, }, } - case http.StatusBadRequest: - return ValidationError{ + case http.StatusForbidden: + return ForbiddenError{ + Error: struct { + Message string `json:"message" example:"Forbidden"` + }{ + Message: message, + }, + } + + case http.StatusNotFound: + return NotFoundError{ Error: struct { - Message string `json:"message"` + Message string `json:"message" example:"Resource not found"` }{ Message: message, }, @@ -102,7 +112,7 @@ func CodeToAPIError(code int, message string) any { default: return ServerError{ Error: struct { - Message string `json:"message"` + Message string `json:"message" example:"Internal server error"` }{ Message: message, }, From cfbe6135e17b86c347649809b3d7508f10822ab5 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:50:54 +0100 Subject: [PATCH 03/31] GO-4459: Return proper api errors and 423 from middleware --- core/api/docs/docs.go | 32 +++++++++++++++++++++++++++++ core/api/docs/swagger.json | 32 +++++++++++++++++++++++++++++ core/api/docs/swagger.yaml | 21 +++++++++++++++++++ core/api/internal/object/handler.go | 2 ++ core/api/internal/space/handler.go | 1 + core/api/server/middleware.go | 16 ++++++++++----- core/api/util/error.go | 16 +++++++++++++++ 7 files changed, 115 insertions(+), 5 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 239cbb9d84..66823dff8e 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -268,6 +268,12 @@ const docTemplate = `{ "$ref": "#/definitions/util.UnauthorizedError" } }, + "423": { + "description": "Rate limit exceeded", + "schema": { + "$ref": "#/definitions/util.RateLimitError" + } + }, "500": { "description": "Internal server error", "schema": { @@ -440,6 +446,12 @@ const docTemplate = `{ "$ref": "#/definitions/util.UnauthorizedError" } }, + "423": { + "description": "Rate limit exceeded", + "schema": { + "$ref": "#/definitions/util.RateLimitError" + } + }, "500": { "description": "Internal server error", "schema": { @@ -556,6 +568,12 @@ const docTemplate = `{ "$ref": "#/definitions/util.NotFoundError" } }, + "423": { + "description": "Rate limit exceeded", + "schema": { + "$ref": "#/definitions/util.RateLimitError" + } + }, "500": { "description": "Internal server error", "schema": { @@ -1725,6 +1743,20 @@ const docTemplate = `{ } } }, + "util.RateLimitError": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Rate limit exceeded" + } + } + } + } + }, "util.ServerError": { "type": "object", "properties": { diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index 72c7919b2c..13034aae6a 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -262,6 +262,12 @@ "$ref": "#/definitions/util.UnauthorizedError" } }, + "423": { + "description": "Rate limit exceeded", + "schema": { + "$ref": "#/definitions/util.RateLimitError" + } + }, "500": { "description": "Internal server error", "schema": { @@ -434,6 +440,12 @@ "$ref": "#/definitions/util.UnauthorizedError" } }, + "423": { + "description": "Rate limit exceeded", + "schema": { + "$ref": "#/definitions/util.RateLimitError" + } + }, "500": { "description": "Internal server error", "schema": { @@ -550,6 +562,12 @@ "$ref": "#/definitions/util.NotFoundError" } }, + "423": { + "description": "Rate limit exceeded", + "schema": { + "$ref": "#/definitions/util.RateLimitError" + } + }, "500": { "description": "Internal server error", "schema": { @@ -1719,6 +1737,20 @@ } } }, + "util.RateLimitError": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Rate limit exceeded" + } + } + } + } + }, "util.ServerError": { "type": "object", "properties": { diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index fbbc53a88e..29f3e2d8f2 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -568,6 +568,15 @@ definitions: type: string type: object type: object + util.RateLimitError: + properties: + error: + properties: + message: + example: Rate limit exceeded + type: string + type: object + type: object util.ServerError: properties: error: @@ -775,6 +784,10 @@ paths: description: Unauthorized schema: $ref: '#/definitions/util.UnauthorizedError' + "423": + description: Rate limit exceeded + schema: + $ref: '#/definitions/util.RateLimitError' "500": description: Internal server error schema: @@ -892,6 +905,10 @@ paths: description: Unauthorized schema: $ref: '#/definitions/util.UnauthorizedError' + "423": + description: Rate limit exceeded + schema: + $ref: '#/definitions/util.RateLimitError' "500": description: Internal server error schema: @@ -933,6 +950,10 @@ paths: description: Resource not found schema: $ref: '#/definitions/util.NotFoundError' + "423": + description: Rate limit exceeded + schema: + $ref: '#/definitions/util.RateLimitError' "500": description: Internal server error schema: diff --git a/core/api/internal/object/handler.go b/core/api/internal/object/handler.go index 671f255839..57c1e2e877 100644 --- a/core/api/internal/object/handler.go +++ b/core/api/internal/object/handler.go @@ -91,6 +91,7 @@ func GetObjectHandler(s *ObjectService) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 403 {object} util.ForbiddenError "Forbidden" // @Failure 404 {object} util.NotFoundError "Resource not found" +// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Router /spaces/{space_id}/objects/{object_id} [delete] func DeleteObjectHandler(s *ObjectService) gin.HandlerFunc { @@ -126,6 +127,7 @@ func DeleteObjectHandler(s *ObjectService) gin.HandlerFunc { // @Success 200 {object} ObjectResponse "The created object" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Router /spaces/{space_id}/objects [post] func CreateObjectHandler(s *ObjectService) gin.HandlerFunc { diff --git a/core/api/internal/space/handler.go b/core/api/internal/space/handler.go index 2a6ca043de..962423a3e0 100644 --- a/core/api/internal/space/handler.go +++ b/core/api/internal/space/handler.go @@ -52,6 +52,7 @@ func GetSpacesHandler(s *SpaceService) gin.HandlerFunc { // @Success 200 {object} CreateSpaceResponse "Space created successfully" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Router /spaces [post] func CreateSpaceHandler(s *SpaceService) gin.HandlerFunc { diff --git a/core/api/server/middleware.go b/core/api/server/middleware.go index da05740b8c..d2a2d23c94 100644 --- a/core/api/server/middleware.go +++ b/core/api/server/middleware.go @@ -11,6 +11,7 @@ import ( "github.com/gin-gonic/gin" "github.com/anyproto/anytype-heart/core/anytype/account" + "github.com/anyproto/anytype-heart/core/api/util" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pb/service" ) @@ -26,7 +27,8 @@ func (s *Server) rateLimit(max float64) gin.HandlerFunc { return func(c *gin.Context) { httpError := tollbooth.LimitByRequest(lmt, c.Writer, c.Request) if httpError != nil { - c.AbortWithStatusJSON(httpError.StatusCode, gin.H{"error": httpError.Message}) + apiErr := util.CodeToAPIError(httpError.StatusCode, httpError.Message) + c.AbortWithStatusJSON(httpError.StatusCode, apiErr) return } c.Next() @@ -38,12 +40,14 @@ func (s *Server) ensureAuthenticated(mw service.ClientCommandsServer) gin.Handle return func(c *gin.Context) { authHeader := c.GetHeader("Authorization") if authHeader == "" { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Missing Authorization header"}) + apiErr := util.CodeToAPIError(http.StatusUnauthorized, "Missing Authorization header") + c.AbortWithStatusJSON(http.StatusUnauthorized, apiErr) return } if !strings.HasPrefix(authHeader, "Bearer ") { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid Authorization header format"}) + apiErr := util.CodeToAPIError(http.StatusUnauthorized, "Invalid Authorization header format") + c.AbortWithStatusJSON(http.StatusUnauthorized, apiErr) return } key := strings.TrimPrefix(authHeader, "Bearer ") @@ -57,7 +61,8 @@ func (s *Server) ensureAuthenticated(mw service.ClientCommandsServer) gin.Handle if !exists { response := mw.WalletCreateSession(context.Background(), &pb.RpcWalletCreateSessionRequest{Auth: &pb.RpcWalletCreateSessionRequestAuthOfAppKey{AppKey: key}}) if response.Error.Code != pb.RpcWalletCreateSessionResponseError_NULL { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + apiErr := util.CodeToAPIError(http.StatusUnauthorized, "Invalid token") + c.AbortWithStatusJSON(http.StatusUnauthorized, apiErr) return } token = response.Token @@ -78,7 +83,8 @@ func (s *Server) ensureAccountInfo(accountService account.Service) gin.HandlerFu return func(c *gin.Context) { accInfo, err := accountService.GetInfo(context.Background()) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to get account info: %v", err)}) + apiErr := util.CodeToAPIError(http.StatusInternalServerError, fmt.Sprintf("failed to get account info: %v", err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, apiErr) return } diff --git a/core/api/util/error.go b/core/api/util/error.go index acec46041c..77aeff751e 100644 --- a/core/api/util/error.go +++ b/core/api/util/error.go @@ -33,6 +33,13 @@ type NotFoundError struct { } `json:"error"` } +// RateLimitError is a struct for 423 errors +type RateLimitError struct { + Error struct { + Message string `json:"message" example:"Rate limit exceeded"` + } `json:"error"` +} + // ServerError is a struct for 500 errors type ServerError struct { Error struct { @@ -109,6 +116,15 @@ func CodeToAPIError(code int, message string) any { }, } + case http.StatusTooManyRequests: + return RateLimitError{ + Error: struct { + Message string `json:"message" example:"Rate limit exceeded"` + }{ + Message: message, + }, + } + default: return ServerError{ Error: struct { From 86975463fdc2f5909f458b1c6f33a76c989b68d6 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Mon, 3 Feb 2025 16:24:56 +0100 Subject: [PATCH 04/31] GO-4459: Add last_modified sort criterion as fallback for last_opened sort --- core/api/internal/search/service.go | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/core/api/internal/search/service.go b/core/api/internal/search/service.go index 58c783ef38..ecd2408718 100644 --- a/core/api/internal/search/service.go +++ b/core/api/internal/search/service.go @@ -48,7 +48,7 @@ func (s *SearchService) GlobalSearch(ctx context.Context, request SearchRequest, baseFilters := s.prepareBaseFilters() queryFilters := s.prepareQueryFilter(request.Query) sorts := s.prepareSorts(request.Sort) - dateToSortAfter := sorts.RelationKey + dateToSortAfter := sorts[0].RelationKey allResponses := make([]*pb.RpcObjectSearchResponse, 0, len(spaces)) for _, space := range spaces { @@ -59,7 +59,7 @@ func (s *SearchService) GlobalSearch(ctx context.Context, request SearchRequest, objResp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: space.Id, Filters: filters, - Sorts: []*model.BlockContentDataviewSort{sorts}, + Sorts: sorts, Keys: []string{bundle.RelationKeyId.String(), bundle.RelationKeySpaceId.String(), dateToSortAfter}, Limit: int32(offset + limit), // nolint: gosec }) @@ -91,7 +91,7 @@ func (s *SearchService) GlobalSearch(ctx context.Context, request SearchRequest, } // sort after posix last_modified_date to achieve descending sort order across all spaces - sort.Slice(combinedRecords, func(i, j int) bool { + sort.SliceStable(combinedRecords, func(i, j int) bool { return combinedRecords[i].DateToSortAfter > combinedRecords[j].DateToSortAfter }) @@ -118,12 +118,12 @@ func (s *SearchService) Search(ctx context.Context, spaceId string, request Sear filters := s.combineFilters(model.BlockContentDataviewFilter_And, baseFilters, queryFilters, typeFilters) sorts := s.prepareSorts(request.Sort) - dateToSortAfter := sorts.RelationKey + dateToSortAfter := sorts[0].RelationKey resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: filters, - Sorts: []*model.BlockContentDataviewSort{sorts}, + Sorts: sorts, Keys: []string{bundle.RelationKeyId.String(), bundle.RelationKeySpaceId.String(), dateToSortAfter}, }) @@ -262,14 +262,28 @@ func (s *SearchService) prepareObjectTypeFilters(spaceId string, objectTypes []s } // prepareSorts returns a sort filter based on the given sort parameters -func (s *SearchService) prepareSorts(sort SortOptions) *model.BlockContentDataviewSort { - return &model.BlockContentDataviewSort{ +func (s *SearchService) prepareSorts(sort SortOptions) []*model.BlockContentDataviewSort { + primarySort := &model.BlockContentDataviewSort{ RelationKey: s.getSortRelationKey(sort.Timestamp), Type: s.getSortDirection(sort.Direction), Format: model.RelationFormat_date, IncludeTime: true, EmptyPlacement: model.BlockContentDataviewSort_NotSpecified, } + + // last_opened_date possibly is empty, wherefore we sort by last_modified_date as secondary criterion + if primarySort.RelationKey == bundle.RelationKeyLastOpenedDate.String() { + secondarySort := &model.BlockContentDataviewSort{ + RelationKey: bundle.RelationKeyLastModifiedDate.String(), + Type: s.getSortDirection(sort.Direction), + Format: model.RelationFormat_date, + IncludeTime: true, + EmptyPlacement: model.BlockContentDataviewSort_NotSpecified, + } + return []*model.BlockContentDataviewSort{primarySort, secondarySort} + } + + return []*model.BlockContentDataviewSort{primarySort} } // getSortRelationKey returns the relation key for the given sort timestamp From 6f238c480fb3b8556022275a44044d831d2904e0 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Mon, 3 Feb 2025 16:25:17 +0100 Subject: [PATCH 05/31] GO-4459: Add ANYTYPE_API_DEBUG to run config --- .run/Run.run.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/.run/Run.run.xml b/.run/Run.run.xml index 47b924fe55..78502fd86d 100644 --- a/.run/Run.run.xml +++ b/.run/Run.run.xml @@ -9,6 +9,7 @@ + From e4fa847daee41b06d9101d5fcbbeeeef9102ef51 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sun, 9 Feb 2025 18:32:21 +0100 Subject: [PATCH 06/31] GO-4459: Add endpoint for single space --- core/api/docs/docs.go | 77 ++++++++++++++++++++++++------ core/api/docs/swagger.json | 77 ++++++++++++++++++++++++------ core/api/docs/swagger.yaml | 48 +++++++++++++++---- core/api/internal/space/handler.go | 36 +++++++++++++- core/api/internal/space/model.go | 8 ++-- core/api/internal/space/service.go | 52 +++++++++++++++++--- core/api/server/router.go | 1 + 7 files changed, 250 insertions(+), 49 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 66823dff8e..75a4a45c81 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -253,7 +253,7 @@ const docTemplate = `{ "200": { "description": "Space created successfully", "schema": { - "$ref": "#/definitions/space.CreateSpaceResponse" + "$ref": "#/definitions/space.SpaceResponse" } }, "400": { @@ -283,6 +283,55 @@ const docTemplate = `{ } } }, + "/spaces/{space_id}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "spaces" + ], + "summary": "Get space", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Space", + "schema": { + "$ref": "#/definitions/space.SpaceResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Space not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + } + }, "/spaces/{space_id}/members": { "get": { "consumes": [ @@ -1556,19 +1605,6 @@ const docTemplate = `{ } } }, - "space.CreateSpaceResponse": { - "type": "object", - "properties": { - "space": { - "description": "The created space", - "allOf": [ - { - "$ref": "#/definitions/space.Space" - } - ] - } - } - }, "space.Member": { "type": "object", "properties": { @@ -1715,6 +1751,19 @@ const docTemplate = `{ } } }, + "space.SpaceResponse": { + "type": "object", + "properties": { + "space": { + "description": "The space", + "allOf": [ + { + "$ref": "#/definitions/space.Space" + } + ] + } + } + }, "util.ForbiddenError": { "type": "object", "properties": { diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index 13034aae6a..edc96b8e6e 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -247,7 +247,7 @@ "200": { "description": "Space created successfully", "schema": { - "$ref": "#/definitions/space.CreateSpaceResponse" + "$ref": "#/definitions/space.SpaceResponse" } }, "400": { @@ -277,6 +277,55 @@ } } }, + "/spaces/{space_id}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "spaces" + ], + "summary": "Get space", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Space", + "schema": { + "$ref": "#/definitions/space.SpaceResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Space not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + } + }, "/spaces/{space_id}/members": { "get": { "consumes": [ @@ -1550,19 +1599,6 @@ } } }, - "space.CreateSpaceResponse": { - "type": "object", - "properties": { - "space": { - "description": "The created space", - "allOf": [ - { - "$ref": "#/definitions/space.Space" - } - ] - } - } - }, "space.Member": { "type": "object", "properties": { @@ -1709,6 +1745,19 @@ } } }, + "space.SpaceResponse": { + "type": "object", + "properties": { + "space": { + "description": "The space", + "allOf": [ + { + "$ref": "#/definitions/space.Space" + } + ] + } + } + }, "util.ForbiddenError": { "type": "object", "properties": { diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 29f3e2d8f2..5e5dd22fbe 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -427,13 +427,6 @@ definitions: example: New Space type: string type: object - space.CreateSpaceResponse: - properties: - space: - allOf: - - $ref: '#/definitions/space.Space' - description: The created space - type: object space.Member: properties: global_name: @@ -550,6 +543,13 @@ definitions: example: bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y type: string type: object + space.SpaceResponse: + properties: + space: + allOf: + - $ref: '#/definitions/space.Space' + description: The space + type: object util.ForbiddenError: properties: error: @@ -775,7 +775,7 @@ paths: "200": description: Space created successfully schema: - $ref: '#/definitions/space.CreateSpaceResponse' + $ref: '#/definitions/space.SpaceResponse' "400": description: Bad request schema: @@ -795,6 +795,38 @@ paths: summary: Create space tags: - spaces + /spaces/{space_id}: + get: + consumes: + - application/json + parameters: + - description: Space ID + in: path + name: space_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: Space + schema: + $ref: '#/definitions/space.SpaceResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/util.UnauthorizedError' + "404": + description: Space not found + schema: + $ref: '#/definitions/util.NotFoundError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/util.ServerError' + summary: Get space + tags: + - spaces /spaces/{space_id}/members: get: consumes: diff --git a/core/api/internal/space/handler.go b/core/api/internal/space/handler.go index 962423a3e0..9aa63043c1 100644 --- a/core/api/internal/space/handler.go +++ b/core/api/internal/space/handler.go @@ -42,6 +42,38 @@ func GetSpacesHandler(s *SpaceService) gin.HandlerFunc { } } +// GetSpaceHandler retrieves a space +// +// @Summary Get space +// @Tags spaces +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Success 200 {object} SpaceResponse "Space" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Space not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /spaces/{space_id} [get] +func GetSpaceHandler(s *SpaceService) gin.HandlerFunc { + return func(c *gin.Context) { + spaceId := c.Param("space_id") + + space, err := s.GetSpace(c.Request.Context(), spaceId) + code := util.MapErrorCode(err, + util.ErrToCode(ErrWorkspaceNotFound, http.StatusNotFound), + util.ErrToCode(ErrFailedOpenWorkspace, http.StatusInternalServerError), + ) + + if code != http.StatusOK { + apiErr := util.CodeToAPIError(code, err.Error()) + c.JSON(code, apiErr) + return + } + + c.JSON(http.StatusOK, SpaceResponse{Space: space}) + } +} + // CreateSpaceHandler creates a new space // // @Summary Create space @@ -49,7 +81,7 @@ func GetSpacesHandler(s *SpaceService) gin.HandlerFunc { // @Accept json // @Produce json // @Param name body CreateSpaceRequest true "Space to create" -// @Success 200 {object} CreateSpaceResponse "Space created successfully" +// @Success 200 {object} SpaceResponse "Space created successfully" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 423 {object} util.RateLimitError "Rate limit exceeded" @@ -75,7 +107,7 @@ func CreateSpaceHandler(s *SpaceService) gin.HandlerFunc { return } - c.JSON(http.StatusOK, CreateSpaceResponse{Space: space}) + c.JSON(http.StatusOK, SpaceResponse{Space: space}) } } diff --git a/core/api/internal/space/model.go b/core/api/internal/space/model.go index 73cbe732be..877978edcd 100644 --- a/core/api/internal/space/model.go +++ b/core/api/internal/space/model.go @@ -1,11 +1,11 @@ package space -type CreateSpaceRequest struct { - Name string `json:"name" example:"New Space"` // The name of the space +type SpaceResponse struct { + Space Space `json:"space"` // The space } -type CreateSpaceResponse struct { - Space Space `json:"space"` // The created space +type CreateSpaceRequest struct { + Name string `json:"name" example:"New Space"` // The name of the space } type Space struct { diff --git a/core/api/internal/space/service.go b/core/api/internal/space/service.go index 9a617b8472..a997e43cc1 100644 --- a/core/api/internal/space/service.go +++ b/core/api/internal/space/service.go @@ -20,6 +20,7 @@ import ( var ( ErrFailedListSpaces = errors.New("failed to retrieve list of spaces") ErrFailedOpenWorkspace = errors.New("failed to open workspace") + ErrWorkspaceNotFound = errors.New("workspace not found") ErrFailedGenerateRandomIcon = errors.New("failed to generate random icon") ErrFailedCreateSpace = errors.New("failed to create space") ErrFailedListMembers = errors.New("failed to retrieve list of members") @@ -27,6 +28,7 @@ var ( type Service interface { ListSpaces(ctx context.Context, offset int, limit int) ([]Space, int, bool, error) + GetSpace(ctx context.Context, spaceId string) (Space, error) CreateSpace(ctx context.Context, name string) (Space, error) ListMembers(ctx context.Context, spaceId string, offset int, limit int) ([]Member, int, bool, error) } @@ -78,21 +80,55 @@ func (s *SpaceService) ListSpaces(ctx context.Context, offset int, limit int) (s spaces = make([]Space, 0, len(paginatedRecords)) for _, record := range paginatedRecords { - workspace, err := s.getWorkspaceInfo(record.Fields[bundle.RelationKeyTargetSpaceId.String()].GetStringValue()) + name := record.Fields[bundle.RelationKeyName.String()].GetStringValue() + icon := util.GetIconFromEmojiOrImage(s.AccountInfo, record.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), record.Fields[bundle.RelationKeyIconImage.String()].GetStringValue()) + + workspace, err := s.getWorkspaceInfo(record.Fields[bundle.RelationKeyTargetSpaceId.String()].GetStringValue(), name, icon) if err != nil { return nil, 0, false, err } - // TODO: name and icon are only returned here; fix that - workspace.Name = record.Fields[bundle.RelationKeyName.String()].GetStringValue() - workspace.Icon = util.GetIconFromEmojiOrImage(s.AccountInfo, record.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), record.Fields[bundle.RelationKeyIconImage.String()].GetStringValue()) - spaces = append(spaces, workspace) } return spaces, total, hasMore, nil } +// GetSpace returns the space info for the space with the given ID. +func (s *SpaceService) GetSpace(ctx context.Context, spaceId string) (Space, error) { + // Check if the workspace exists and is active + resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ + SpaceId: s.AccountInfo.TechSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyTargetSpaceId.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.String(spaceId), + }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeySpaceLocalStatus.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.Int64(int64(model.SpaceStatus_Ok)), + }, + }, + Keys: []string{bundle.RelationKeyTargetSpaceId.String()}, + }) + + if resp.Error.Code != pb.RpcObjectSearchResponseError_NULL { + return Space{}, ErrFailedOpenWorkspace + } + + if len(resp.Records) == 0 { + return Space{}, ErrWorkspaceNotFound + } + + name := resp.Records[0].Fields[bundle.RelationKeyName.String()].GetStringValue() + icon := util.GetIconFromEmojiOrImage(s.AccountInfo, resp.Records[0].Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), resp.Records[0].Fields[bundle.RelationKeyIconImage.String()].GetStringValue()) + return s.getWorkspaceInfo(spaceId, name, icon) +} + // CreateSpace creates a new space with the given name and returns the space info. func (s *SpaceService) CreateSpace(ctx context.Context, name string) (Space, error) { iconOption, err := rand.Int(rand.Reader, big.NewInt(13)) @@ -117,7 +153,7 @@ func (s *SpaceService) CreateSpace(ctx context.Context, name string) (Space, err return Space{}, ErrFailedCreateSpace } - return s.getWorkspaceInfo(resp.SpaceId) + return s.getWorkspaceInfo(resp.SpaceId, name, "") } // ListMembers returns a paginated list of members in the space with the given ID. @@ -210,7 +246,7 @@ func (s *SpaceService) GetParticipantDetails(mw service.ClientCommandsServer, sp } // getWorkspaceInfo returns the workspace info for the space with the given ID. -func (s *SpaceService) getWorkspaceInfo(spaceId string) (space Space, err error) { +func (s *SpaceService) getWorkspaceInfo(spaceId string, name string, icon string) (space Space, err error) { workspaceResponse := s.mw.WorkspaceOpen(context.Background(), &pb.RpcWorkspaceOpenRequest{ SpaceId: spaceId, WithChat: true, @@ -223,6 +259,8 @@ func (s *SpaceService) getWorkspaceInfo(spaceId string) (space Space, err error) return Space{ Type: "space", Id: spaceId, + Name: name, + Icon: icon, HomeObjectId: workspaceResponse.Info.HomeObjectId, ArchiveObjectId: workspaceResponse.Info.ArchiveObjectId, ProfileObjectId: workspaceResponse.Info.ProfileObjectId, diff --git a/core/api/server/router.go b/core/api/server/router.go index e33206a325..d0467e9360 100644 --- a/core/api/server/router.go +++ b/core/api/server/router.go @@ -78,6 +78,7 @@ func (s *Server) NewRouter(accountService account.Service, mw service.ClientComm // Space v1.GET("/spaces", space.GetSpacesHandler(s.spaceService)) + v1.GET("/spaces/:space_id", space.GetSpaceHandler(s.spaceService)) v1.GET("/spaces/:space_id/members", space.GetMembersHandler(s.spaceService)) v1.POST("/spaces", s.rateLimit(maxWriteRequestsPerSecond), space.CreateSpaceHandler(s.spaceService)) From da5299019d9ced4e406d4341e43fe1ffec812736 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sun, 9 Feb 2025 19:02:18 +0100 Subject: [PATCH 07/31] GO-4459: Add missing relation keys in GetSpace --- core/api/internal/space/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/api/internal/space/service.go b/core/api/internal/space/service.go index a997e43cc1..b9c27bb576 100644 --- a/core/api/internal/space/service.go +++ b/core/api/internal/space/service.go @@ -113,7 +113,7 @@ func (s *SpaceService) GetSpace(ctx context.Context, spaceId string) (Space, err Value: pbtypes.Int64(int64(model.SpaceStatus_Ok)), }, }, - Keys: []string{bundle.RelationKeyTargetSpaceId.String()}, + Keys: []string{bundle.RelationKeyTargetSpaceId.String(), bundle.RelationKeyName.String(), bundle.RelationKeyIconEmoji.String(), bundle.RelationKeyIconImage.String()}, }) if resp.Error.Code != pb.RpcObjectSearchResponseError_NULL { From 2010b1a2a37c3708b3782ce59e5ebc7ccc75e9a1 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sun, 9 Feb 2025 19:31:07 +0100 Subject: [PATCH 08/31] GO-4459: Add endpoint for single member --- core/api/docs/docs.go | 69 +++++++++++++++++++++++++++++ core/api/docs/swagger.json | 69 +++++++++++++++++++++++++++++ core/api/docs/swagger.yaml | 44 ++++++++++++++++++ core/api/internal/object/service.go | 14 +++++- core/api/internal/space/handler.go | 34 ++++++++++++++ core/api/internal/space/model.go | 4 ++ core/api/internal/space/service.go | 16 ++++--- core/api/server/router.go | 1 + 8 files changed, 243 insertions(+), 8 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 75a4a45c81..79214ab946 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -390,6 +390,62 @@ const docTemplate = `{ } } }, + "/spaces/{space_id}/members/{member_id}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "spaces" + ], + "summary": "Get member", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Member ID", + "name": "member_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Member", + "schema": { + "$ref": "#/definitions/space.MemberResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Member not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + } + }, "/spaces/{space_id}/objects": { "get": { "consumes": [ @@ -1651,6 +1707,19 @@ const docTemplate = `{ } } }, + "space.MemberResponse": { + "type": "object", + "properties": { + "member": { + "description": "The member", + "allOf": [ + { + "$ref": "#/definitions/space.Member" + } + ] + } + } + }, "space.Space": { "type": "object", "properties": { diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index edc96b8e6e..7978d53c05 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -384,6 +384,62 @@ } } }, + "/spaces/{space_id}/members/{member_id}": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "spaces" + ], + "summary": "Get member", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Member ID", + "name": "member_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Member", + "schema": { + "$ref": "#/definitions/space.MemberResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Member not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + } + }, "/spaces/{space_id}/objects": { "get": { "consumes": [ @@ -1645,6 +1701,19 @@ } } }, + "space.MemberResponse": { + "type": "object", + "properties": { + "member": { + "description": "The member", + "allOf": [ + { + "$ref": "#/definitions/space.Member" + } + ] + } + } + }, "space.Space": { "type": "object", "properties": { diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 5e5dd22fbe..1f1b9a7690 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -463,6 +463,13 @@ definitions: example: member type: string type: object + space.MemberResponse: + properties: + member: + allOf: + - $ref: '#/definitions/space.Member' + description: The member + type: object space.Space: properties: account_space_id: @@ -867,6 +874,43 @@ paths: summary: List members tags: - spaces + /spaces/{space_id}/members/{member_id}: + get: + consumes: + - application/json + parameters: + - description: Space ID + in: path + name: space_id + required: true + type: string + - description: Member ID + in: path + name: member_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: Member + schema: + $ref: '#/definitions/space.MemberResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/util.UnauthorizedError' + "404": + description: Member not found + schema: + $ref: '#/definitions/util.NotFoundError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/util.ServerError' + summary: Get member + tags: + - spaces /spaces/{space_id}/objects: get: consumes: diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index 91efda7b20..284a588ad3 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -447,6 +447,16 @@ func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { } } + memberLastModifiedBy, err := s.spaceService.GetMember(context.Background(), resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), lastModifiedById) + if err != nil { + memberLastModifiedBy = space.Member{} + } + + memberCreator, err := s.spaceService.GetMember(context.Background(), resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), creatorId) + if err != nil { + memberCreator = space.Member{} + } + return []Detail{ { Id: "last_modified_date", @@ -457,7 +467,7 @@ func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { { Id: "last_modified_by", Details: map[string]interface{}{ - "details": s.spaceService.GetParticipantDetails(s.mw, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), lastModifiedById), + "details": memberLastModifiedBy, }, }, { @@ -469,7 +479,7 @@ func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { { Id: "created_by", Details: map[string]interface{}{ - "details": s.spaceService.GetParticipantDetails(s.mw, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), creatorId), + "details": memberCreator, }, }, { diff --git a/core/api/internal/space/handler.go b/core/api/internal/space/handler.go index 9aa63043c1..5dbbd2cd83 100644 --- a/core/api/internal/space/handler.go +++ b/core/api/internal/space/handler.go @@ -144,3 +144,37 @@ func GetMembersHandler(s *SpaceService) gin.HandlerFunc { pagination.RespondWithPagination(c, http.StatusOK, members, total, offset, limit, hasMore) } } + +// GetMemberHandler retrieves a member in a space +// +// @Summary Get member +// @Tags spaces +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param member_id path string true "Member ID" +// @Success 200 {object} MemberResponse "Member" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Member not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /spaces/{space_id}/members/{member_id} [get] +func GetMemberHandler(s *SpaceService) gin.HandlerFunc { + return func(c *gin.Context) { + spaceId := c.Param("space_id") + memberId := c.Param("member_id") + + member, err := s.GetMember(c.Request.Context(), spaceId, memberId) + code := util.MapErrorCode(err, + util.ErrToCode(ErrMemberNotFound, http.StatusNotFound), + util.ErrToCode(ErrFailedGetMember, http.StatusInternalServerError), + ) + + if code != http.StatusOK { + apiErr := util.CodeToAPIError(code, err.Error()) + c.JSON(code, apiErr) + return + } + + c.JSON(http.StatusOK, MemberResponse{Member: member}) + } +} diff --git a/core/api/internal/space/model.go b/core/api/internal/space/model.go index 877978edcd..6805de3ccb 100644 --- a/core/api/internal/space/model.go +++ b/core/api/internal/space/model.go @@ -30,6 +30,10 @@ type Space struct { NetworkId string `json:"network_id" example:"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU"` // The network id of the space } +type MemberResponse struct { + Member Member `json:"member"` // The member +} + type Member struct { Type string `json:"type" example:"member"` // The type of the object Id string `json:"id" example:"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ"` // The profile object id of the member diff --git a/core/api/internal/space/service.go b/core/api/internal/space/service.go index b9c27bb576..eb83f636c7 100644 --- a/core/api/internal/space/service.go +++ b/core/api/internal/space/service.go @@ -24,6 +24,8 @@ var ( ErrFailedGenerateRandomIcon = errors.New("failed to generate random icon") ErrFailedCreateSpace = errors.New("failed to create space") ErrFailedListMembers = errors.New("failed to retrieve list of members") + ErrFailedGetMember = errors.New("failed to retrieve member") + ErrMemberNotFound = errors.New("member not found") ) type Service interface { @@ -31,6 +33,7 @@ type Service interface { GetSpace(ctx context.Context, spaceId string) (Space, error) CreateSpace(ctx context.Context, name string) (Space, error) ListMembers(ctx context.Context, spaceId string, offset int, limit int) ([]Member, int, bool, error) + GetMember(ctx context.Context, spaceId string, memberId string) (Member, error) } type SpaceService struct { @@ -210,26 +213,27 @@ func (s *SpaceService) ListMembers(ctx context.Context, spaceId string, offset i return members, total, hasMore, nil } -func (s *SpaceService) GetParticipantDetails(mw service.ClientCommandsServer, spaceId string, participantId string) Member { - resp := mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ +// GetMember returns the member with the given ID in the space with the given ID. +func (s *SpaceService) GetMember(ctx context.Context, spaceId string, memberId string) (Member, error) { + resp := s.mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { Operator: model.BlockContentDataviewFilter_No, RelationKey: bundle.RelationKeyId.String(), Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(participantId), + Value: pbtypes.String(memberId), }, }, Keys: []string{bundle.RelationKeyId.String(), bundle.RelationKeyName.String(), bundle.RelationKeyIconEmoji.String(), bundle.RelationKeyIconImage.String(), bundle.RelationKeyIdentity.String(), bundle.RelationKeyGlobalName.String(), bundle.RelationKeyParticipantPermissions.String()}, }) if resp.Error.Code != pb.RpcObjectSearchResponseError_NULL { - return Member{} + return Member{}, ErrFailedGetMember } if len(resp.Records) == 0 { - return Member{} + return Member{}, ErrMemberNotFound } icon := util.GetIconFromEmojiOrImage(s.AccountInfo, "", resp.Records[0].Fields[bundle.RelationKeyIconImage.String()].GetStringValue()) @@ -242,7 +246,7 @@ func (s *SpaceService) GetParticipantDetails(mw service.ClientCommandsServer, sp Identity: resp.Records[0].Fields[bundle.RelationKeyIdentity.String()].GetStringValue(), GlobalName: resp.Records[0].Fields[bundle.RelationKeyGlobalName.String()].GetStringValue(), Role: model.ParticipantPermissions_name[int32(resp.Records[0].Fields[bundle.RelationKeyParticipantPermissions.String()].GetNumberValue())], - } + }, nil } // getWorkspaceInfo returns the workspace info for the space with the given ID. diff --git a/core/api/server/router.go b/core/api/server/router.go index d0467e9360..ed1b00a990 100644 --- a/core/api/server/router.go +++ b/core/api/server/router.go @@ -80,6 +80,7 @@ func (s *Server) NewRouter(accountService account.Service, mw service.ClientComm v1.GET("/spaces", space.GetSpacesHandler(s.spaceService)) v1.GET("/spaces/:space_id", space.GetSpaceHandler(s.spaceService)) v1.GET("/spaces/:space_id/members", space.GetMembersHandler(s.spaceService)) + v1.GET("/spaces/:space_id/members/:member_id", space.GetMemberHandler(s.spaceService)) v1.POST("/spaces", s.rateLimit(maxWriteRequestsPerSecond), space.CreateSpaceHandler(s.spaceService)) // Type From 544d9488c7f8b4b7f42558348fb299e0bf1bc054 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Wed, 12 Feb 2025 12:17:47 +0100 Subject: [PATCH 09/31] GO-4459: Add handlers and routes for list endpoints --- core/api/docs/docs.go | 285 ++++++++++++++++++++++++++++ core/api/docs/swagger.json | 285 ++++++++++++++++++++++++++++ core/api/docs/swagger.yaml | 191 +++++++++++++++++++ core/api/internal/export/service.go | 3 +- core/api/internal/list/handler.go | 173 +++++++++++++++++ core/api/internal/list/service.go | 51 +++++ core/api/server/middleware.go | 1 - core/api/server/router.go | 7 + core/api/server/server.go | 3 + 9 files changed, 996 insertions(+), 3 deletions(-) create mode 100644 core/api/internal/list/handler.go create mode 100644 core/api/internal/list/service.go diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 79214ab946..8283877be5 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -1063,6 +1063,291 @@ const docTemplate = `{ } } } + }, + "/v1/spaces/{space_id}/lists/{list_id}/objects": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "list" + ], + "summary": "Get objects in list", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "List ID", + "name": "list_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "default": 0, + "description": "The number of items to skip before starting to collect the result set", + "name": "offset", + "in": "query" + }, + { + "type": "integer", + "description": "The number of items to return", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of objects", + "schema": { + "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "list" + ], + "summary": "Add objects to list", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "List ID", + "name": "list_id", + "in": "path", + "required": true + }, + { + "description": "List of object IDs", + "name": "objects", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Objects added successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/util.ValidationError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "list" + ], + "summary": "Remove objects from list", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "List ID", + "name": "list_id", + "in": "path", + "required": true + }, + { + "description": "List of object IDs", + "name": "objects", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Objects removed successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/util.ValidationError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + }, + "patch": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "list" + ], + "summary": "Update object order in list", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "List ID", + "name": "list_id", + "in": "path", + "required": true + }, + { + "description": "List of object IDs", + "name": "objects", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Objects updated successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/util.ValidationError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + } } }, "definitions": { diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index 7978d53c05..2de24feafc 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -1057,6 +1057,291 @@ } } } + }, + "/v1/spaces/{space_id}/lists/{list_id}/objects": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "list" + ], + "summary": "Get objects in list", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "List ID", + "name": "list_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "default": 0, + "description": "The number of items to skip before starting to collect the result set", + "name": "offset", + "in": "query" + }, + { + "type": "integer", + "description": "The number of items to return", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of objects", + "schema": { + "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "list" + ], + "summary": "Add objects to list", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "List ID", + "name": "list_id", + "in": "path", + "required": true + }, + { + "description": "List of object IDs", + "name": "objects", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Objects added successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/util.ValidationError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "list" + ], + "summary": "Remove objects from list", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "List ID", + "name": "list_id", + "in": "path", + "required": true + }, + { + "description": "List of object IDs", + "name": "objects", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Objects removed successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/util.ValidationError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + }, + "patch": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "list" + ], + "summary": "Update object order in list", + "parameters": [ + { + "type": "string", + "description": "Space ID", + "name": "space_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "List ID", + "name": "list_id", + "in": "path", + "required": true + }, + { + "description": "List of object IDs", + "name": "objects", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Objects updated successfully", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/util.ValidationError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/util.UnauthorizedError" + } + }, + "404": { + "description": "Not found", + "schema": { + "$ref": "#/definitions/util.NotFoundError" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/util.ServerError" + } + } + } + } } }, "definitions": { diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 1f1b9a7690..61b43ac732 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -1328,6 +1328,197 @@ paths: summary: Get template tags: - types + /v1/spaces/{space_id}/lists/{list_id}/objects: + delete: + consumes: + - application/json + parameters: + - description: Space ID + in: path + name: space_id + required: true + type: string + - description: List ID + in: path + name: list_id + required: true + type: string + - description: List of object IDs + in: body + name: objects + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: Objects removed successfully + schema: + type: string + "400": + description: Bad request + schema: + $ref: '#/definitions/util.ValidationError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/util.UnauthorizedError' + "404": + description: Not found + schema: + $ref: '#/definitions/util.NotFoundError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/util.ServerError' + summary: Remove objects from list + tags: + - list + get: + consumes: + - application/json + parameters: + - description: Space ID + in: path + name: space_id + required: true + type: string + - description: List ID + in: path + name: list_id + required: true + type: string + - default: 0 + description: The number of items to skip before starting to collect the result + set + in: query + name: offset + type: integer + - description: The number of items to return + in: query + name: limit + type: integer + produces: + - application/json + responses: + "200": + description: List of objects + schema: + $ref: '#/definitions/pagination.PaginatedResponse-object_Object' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/util.UnauthorizedError' + "404": + description: Not found + schema: + $ref: '#/definitions/util.NotFoundError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/util.ServerError' + summary: Get objects in list + tags: + - list + patch: + consumes: + - application/json + parameters: + - description: Space ID + in: path + name: space_id + required: true + type: string + - description: List ID + in: path + name: list_id + required: true + type: string + - description: List of object IDs + in: body + name: objects + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: Objects updated successfully + schema: + type: string + "400": + description: Bad request + schema: + $ref: '#/definitions/util.ValidationError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/util.UnauthorizedError' + "404": + description: Not found + schema: + $ref: '#/definitions/util.NotFoundError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/util.ServerError' + summary: Update object order in list + tags: + - list + post: + consumes: + - application/json + parameters: + - description: Space ID + in: path + name: space_id + required: true + type: string + - description: List ID + in: path + name: list_id + required: true + type: string + - description: List of object IDs + in: body + name: objects + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: Objects added successfully + schema: + type: string + "400": + description: Bad request + schema: + $ref: '#/definitions/util.ValidationError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/util.UnauthorizedError' + "404": + description: Not found + schema: + $ref: '#/definitions/util.NotFoundError' + "500": + description: Internal server error + schema: + $ref: '#/definitions/util.ServerError' + summary: Add objects to list + tags: + - list securityDefinitions: BasicAuth: type: basic diff --git a/core/api/internal/export/service.go b/core/api/internal/export/service.go index b20361351c..bcb4e4e338 100644 --- a/core/api/internal/export/service.go +++ b/core/api/internal/export/service.go @@ -19,8 +19,7 @@ type Service interface { } type ExportService struct { - mw service.ClientCommandsServer - AccountInfo *model.AccountInfo + mw service.ClientCommandsServer } func NewService(mw service.ClientCommandsServer) *ExportService { diff --git a/core/api/internal/list/handler.go b/core/api/internal/list/handler.go new file mode 100644 index 0000000000..f7e6ad959d --- /dev/null +++ b/core/api/internal/list/handler.go @@ -0,0 +1,173 @@ +package list + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + "github.com/anyproto/anytype-heart/core/api/pagination" + "github.com/anyproto/anytype-heart/core/api/util" +) + +// GetObjectsInListHandler +// +// @Summary Get objects in list +// @Tags list +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param list_id path string true "List ID" +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" +// @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [get] +func GetObjectsInListHandler(s *ListService) gin.HandlerFunc { + return func(c *gin.Context) { + spaceID := c.Param("space_id") + listID := c.Param("list_id") + offset := c.GetInt("offset") + limit := c.GetInt("limit") + + objects, total, hasMore, err := s.GetObjectsInList(c, spaceID, listID, offset, limit) + code := util.MapErrorCode(err, + util.ErrToCode(ErrFailedGetObjectsInList, http.StatusInternalServerError), + ) + + if code != http.StatusOK { + apiErr := util.CodeToAPIError(code, err.Error()) + c.JSON(code, apiErr) + return + } + + pagination.RespondWithPagination(c, http.StatusOK, objects, total, offset, limit, hasMore) + } +} + +// AddObjectsToListHandler +// +// @Summary Add objects to list +// @Tags list +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param list_id path string true "List ID" +// @Param objects body []string true "List of object IDs" +// @Success 200 {object} string "Objects added successfully" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [post] +func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { + return func(c *gin.Context) { + spaceID := c.Param("space_id") + listID := c.Param("list_id") + + objects := []string{} + if err := c.ShouldBindJSON(&objects); err != nil { + apiErr := util.CodeToAPIError(http.StatusBadRequest, err.Error()) + c.JSON(http.StatusBadRequest, apiErr) + return + } + + err := s.AddObjectsToList(c, spaceID, listID, objects) + code := util.MapErrorCode(err, + util.ErrToCode(ErrFailedAddObjectsToList, http.StatusInternalServerError), + ) + + if code != http.StatusOK { + apiErr := util.CodeToAPIError(code, err.Error()) + c.JSON(code, apiErr) + return + } + + c.JSON(http.StatusOK, "Objects added successfully") + } +} + +// RemoveObjectsFromListHandler +// +// @Summary Remove objects from list +// @Tags list +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param list_id path string true "List ID" +// @Param objects body []string true "List of object IDs" +// @Success 200 {object} string "Objects removed successfully" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [delete] +func RemoveObjectsFromListHandler(s *ListService) gin.HandlerFunc { + return func(c *gin.Context) { + spaceID := c.Param("space_id") + listID := c.Param("list_id") + + objects := []string{} + if err := c.ShouldBindJSON(&objects); err != nil { + apiErr := util.CodeToAPIError(http.StatusBadRequest, err.Error()) + c.JSON(http.StatusBadRequest, apiErr) + return + } + + err := s.RemoveObjectsFromList(c, spaceID, listID, objects) + code := util.MapErrorCode(err, + util.ErrToCode(ErrFailedRemoveObjectsFromList, http.StatusInternalServerError), + ) + + if code != http.StatusOK { + apiErr := util.CodeToAPIError(code, err.Error()) + c.JSON(code, apiErr) + return + } + + c.JSON(http.StatusOK, "Objects removed successfully") + } +} + +// UpdateObjectsInListHandler +// +// @Summary Update object order in list +// @Tags list +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param list_id path string true "List ID" +// @Param objects body []string true "List of object IDs" +// @Success 200 {object} string "Objects updated successfully" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [patch] +func UpdateObjectsInListHandler(s *ListService) gin.HandlerFunc { + return func(c *gin.Context) { + spaceID := c.Param("space_id") + listID := c.Param("list_id") + + objects := []string{} + if err := c.ShouldBindJSON(&objects); err != nil { + apiErr := util.CodeToAPIError(http.StatusBadRequest, err.Error()) + c.JSON(http.StatusBadRequest, apiErr) + return + } + + err := s.UpdateObjectsInList(c, spaceID, listID, objects) + code := util.MapErrorCode(err, + util.ErrToCode(ErrFailedUpdateObjectsInList, http.StatusInternalServerError), + ) + + if code != http.StatusOK { + apiErr := util.CodeToAPIError(code, err.Error()) + c.JSON(code, apiErr) + return + } + + c.JSON(http.StatusOK, "Objects updated successfully") + } +} diff --git a/core/api/internal/list/service.go b/core/api/internal/list/service.go new file mode 100644 index 0000000000..b55868718d --- /dev/null +++ b/core/api/internal/list/service.go @@ -0,0 +1,51 @@ +package list + +import ( + "context" + "errors" + + "github.com/anyproto/anytype-heart/pb/service" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" +) + +var ( + ErrFailedGetObjectsInList = errors.New("failed to get objects in list") + ErrFailedAddObjectsToList = errors.New("failed to add objects to list") + ErrFailedRemoveObjectsFromList = errors.New("failed to remove objects from list") + ErrFailedUpdateObjectsInList = errors.New("failed to update objects in list") +) + +type Service interface { + GetObjectsInList(ctx context.Context, spaceId string, listId string, offset, limit int) ([]*model.Object, int, bool, error) + AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIDs []string) error + RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIDs []string) error + UpdateObjectsInList(ctx context.Context, spaceId string, listId string, objectIDs []string) error +} + +type ListService struct { + mw service.ClientCommandsServer +} + +func NewService(mw service.ClientCommandsServer) *ListService { + return &ListService{mw: mw} +} + +// GetObjectsInList retrieves objects in a list +func (s *ListService) GetObjectsInList(ctx context.Context, spaceId string, listId string, offset, limit int) ([]*model.Object, int, bool, error) { + return nil, 0, false, nil +} + +// AddObjectsToList adds objects to a list +func (s *ListService) AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIDs []string) error { + return nil +} + +// RemoveObjectsFromList removes objects from a list +func (s *ListService) RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIDs []string) error { + return nil +} + +// UpdateObjectsInList updates an object in a list +func (s *ListService) UpdateObjectsInList(ctx context.Context, spaceId string, listId string, objectIDs []string) error { + return nil +} diff --git a/core/api/server/middleware.go b/core/api/server/middleware.go index d2a2d23c94..1313127f80 100644 --- a/core/api/server/middleware.go +++ b/core/api/server/middleware.go @@ -88,7 +88,6 @@ func (s *Server) ensureAccountInfo(accountService account.Service) gin.HandlerFu return } - s.exportService.AccountInfo = accInfo s.objectService.AccountInfo = accInfo s.spaceService.AccountInfo = accInfo s.searchService.AccountInfo = accInfo diff --git a/core/api/server/router.go b/core/api/server/router.go index ed1b00a990..f7aad0482d 100644 --- a/core/api/server/router.go +++ b/core/api/server/router.go @@ -12,6 +12,7 @@ import ( "github.com/anyproto/anytype-heart/core/anytype/account" "github.com/anyproto/anytype-heart/core/api/internal/auth" "github.com/anyproto/anytype-heart/core/api/internal/export" + "github.com/anyproto/anytype-heart/core/api/internal/list" "github.com/anyproto/anytype-heart/core/api/internal/object" "github.com/anyproto/anytype-heart/core/api/internal/search" "github.com/anyproto/anytype-heart/core/api/internal/space" @@ -66,6 +67,12 @@ func (s *Server) NewRouter(accountService account.Service, mw service.ClientComm // Export v1.POST("/spaces/:space_id/objects/:object_id/export/:format", export.GetObjectExportHandler(s.exportService)) + // List + v1.GET("/v1/spaces/:space_id/lists/:list_id/objects", list.GetObjectsInListHandler(s.listService)) + v1.POST("/v1/spaces/:space_id/lists/:list_id/objects", list.AddObjectsToListHandler(s.listService)) + v1.DELETE("/v1/spaces/:space_id/lists/:list_id/objects", list.RemoveObjectsFromListHandler(s.listService)) + v1.PATCH("/v1/spaces/:space_id/lists/:list_id/objects", list.UpdateObjectsInListHandler(s.listService)) + // Object v1.GET("/spaces/:space_id/objects", object.GetObjectsHandler(s.objectService)) v1.GET("/spaces/:space_id/objects/:object_id", object.GetObjectHandler(s.objectService)) diff --git a/core/api/server/server.go b/core/api/server/server.go index 78fb467932..56b312d699 100644 --- a/core/api/server/server.go +++ b/core/api/server/server.go @@ -8,6 +8,7 @@ import ( "github.com/anyproto/anytype-heart/core/anytype/account" "github.com/anyproto/anytype-heart/core/api/internal/auth" "github.com/anyproto/anytype-heart/core/api/internal/export" + "github.com/anyproto/anytype-heart/core/api/internal/list" "github.com/anyproto/anytype-heart/core/api/internal/object" "github.com/anyproto/anytype-heart/core/api/internal/search" "github.com/anyproto/anytype-heart/core/api/internal/space" @@ -20,6 +21,7 @@ type Server struct { authService *auth.AuthService exportService *export.ExportService + listService *list.ListService objectService *object.ObjectService spaceService *space.SpaceService searchService *search.SearchService @@ -33,6 +35,7 @@ func NewServer(accountService account.Service, mw service.ClientCommandsServer) s := &Server{ authService: auth.NewService(mw), exportService: export.NewService(mw), + listService: list.NewService(mw), spaceService: space.NewService(mw), } From 526de3ccd31f407213316ab61867c3f0e39e186f Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Wed, 12 Feb 2025 15:47:05 +0100 Subject: [PATCH 10/31] GO-4459: Add initial list service implementation --- core/api/docs/docs.go | 8 +-- core/api/docs/swagger.json | 8 +-- core/api/docs/swagger.yaml | 8 +-- core/api/internal/list/handler.go | 32 ++++++------ core/api/internal/list/service.go | 85 +++++++++++++++++++++++++++---- core/api/server/server.go | 2 +- 6 files changed, 103 insertions(+), 40 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 8283877be5..f158831eb6 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -1073,7 +1073,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "list" + "lists" ], "summary": "Get objects in list", "parameters": [ @@ -1140,7 +1140,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "list" + "lists" ], "summary": "Add objects to list", "parameters": [ @@ -1212,7 +1212,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "list" + "lists" ], "summary": "Remove objects from list", "parameters": [ @@ -1284,7 +1284,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "list" + "lists" ], "summary": "Update object order in list", "parameters": [ diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index 2de24feafc..0d063df110 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -1067,7 +1067,7 @@ "application/json" ], "tags": [ - "list" + "lists" ], "summary": "Get objects in list", "parameters": [ @@ -1134,7 +1134,7 @@ "application/json" ], "tags": [ - "list" + "lists" ], "summary": "Add objects to list", "parameters": [ @@ -1206,7 +1206,7 @@ "application/json" ], "tags": [ - "list" + "lists" ], "summary": "Remove objects from list", "parameters": [ @@ -1278,7 +1278,7 @@ "application/json" ], "tags": [ - "list" + "lists" ], "summary": "Update object order in list", "parameters": [ diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 61b43ac732..5f31973fac 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -1376,7 +1376,7 @@ paths: $ref: '#/definitions/util.ServerError' summary: Remove objects from list tags: - - list + - lists get: consumes: - application/json @@ -1422,7 +1422,7 @@ paths: $ref: '#/definitions/util.ServerError' summary: Get objects in list tags: - - list + - lists patch: consumes: - application/json @@ -1470,7 +1470,7 @@ paths: $ref: '#/definitions/util.ServerError' summary: Update object order in list tags: - - list + - lists post: consumes: - application/json @@ -1518,7 +1518,7 @@ paths: $ref: '#/definitions/util.ServerError' summary: Add objects to list tags: - - list + - lists securityDefinitions: BasicAuth: type: basic diff --git a/core/api/internal/list/handler.go b/core/api/internal/list/handler.go index f7e6ad959d..e1e7fbd75c 100644 --- a/core/api/internal/list/handler.go +++ b/core/api/internal/list/handler.go @@ -12,7 +12,7 @@ import ( // GetObjectsInListHandler // // @Summary Get objects in list -// @Tags list +// @Tags lists // @Accept json // @Produce json // @Param space_id path string true "Space ID" @@ -26,12 +26,12 @@ import ( // @Router /v1/spaces/{space_id}/lists/{list_id}/objects [get] func GetObjectsInListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { - spaceID := c.Param("space_id") - listID := c.Param("list_id") + spaceId := c.Param("space_id") + listId := c.Param("list_id") offset := c.GetInt("offset") limit := c.GetInt("limit") - objects, total, hasMore, err := s.GetObjectsInList(c, spaceID, listID, offset, limit) + objects, total, hasMore, err := s.GetObjectsInList(c, spaceId, listId, offset, limit) code := util.MapErrorCode(err, util.ErrToCode(ErrFailedGetObjectsInList, http.StatusInternalServerError), ) @@ -49,7 +49,7 @@ func GetObjectsInListHandler(s *ListService) gin.HandlerFunc { // AddObjectsToListHandler // // @Summary Add objects to list -// @Tags list +// @Tags lists // @Accept json // @Produce json // @Param space_id path string true "Space ID" @@ -63,8 +63,8 @@ func GetObjectsInListHandler(s *ListService) gin.HandlerFunc { // @Router /v1/spaces/{space_id}/lists/{list_id}/objects [post] func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { - spaceID := c.Param("space_id") - listID := c.Param("list_id") + spaceId := c.Param("space_id") + listId := c.Param("list_id") objects := []string{} if err := c.ShouldBindJSON(&objects); err != nil { @@ -73,7 +73,7 @@ func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { return } - err := s.AddObjectsToList(c, spaceID, listID, objects) + err := s.AddObjectsToList(c, spaceId, listId, objects) code := util.MapErrorCode(err, util.ErrToCode(ErrFailedAddObjectsToList, http.StatusInternalServerError), ) @@ -91,7 +91,7 @@ func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { // RemoveObjectsFromListHandler // // @Summary Remove objects from list -// @Tags list +// @Tags lists // @Accept json // @Produce json // @Param space_id path string true "Space ID" @@ -105,8 +105,8 @@ func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { // @Router /v1/spaces/{space_id}/lists/{list_id}/objects [delete] func RemoveObjectsFromListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { - spaceID := c.Param("space_id") - listID := c.Param("list_id") + spaceId := c.Param("space_id") + listId := c.Param("list_id") objects := []string{} if err := c.ShouldBindJSON(&objects); err != nil { @@ -115,7 +115,7 @@ func RemoveObjectsFromListHandler(s *ListService) gin.HandlerFunc { return } - err := s.RemoveObjectsFromList(c, spaceID, listID, objects) + err := s.RemoveObjectsFromList(c, spaceId, listId, objects) code := util.MapErrorCode(err, util.ErrToCode(ErrFailedRemoveObjectsFromList, http.StatusInternalServerError), ) @@ -133,7 +133,7 @@ func RemoveObjectsFromListHandler(s *ListService) gin.HandlerFunc { // UpdateObjectsInListHandler // // @Summary Update object order in list -// @Tags list +// @Tags lists // @Accept json // @Produce json // @Param space_id path string true "Space ID" @@ -147,8 +147,8 @@ func RemoveObjectsFromListHandler(s *ListService) gin.HandlerFunc { // @Router /v1/spaces/{space_id}/lists/{list_id}/objects [patch] func UpdateObjectsInListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { - spaceID := c.Param("space_id") - listID := c.Param("list_id") + spaceId := c.Param("space_id") + listId := c.Param("list_id") objects := []string{} if err := c.ShouldBindJSON(&objects); err != nil { @@ -157,7 +157,7 @@ func UpdateObjectsInListHandler(s *ListService) gin.HandlerFunc { return } - err := s.UpdateObjectsInList(c, spaceID, listID, objects) + err := s.UpdateObjectsInList(c, spaceId, listId, objects) code := util.MapErrorCode(err, util.ErrToCode(ErrFailedUpdateObjectsInList, http.StatusInternalServerError), ) diff --git a/core/api/internal/list/service.go b/core/api/internal/list/service.go index b55868718d..943035c440 100644 --- a/core/api/internal/list/service.go +++ b/core/api/internal/list/service.go @@ -4,7 +4,11 @@ import ( "context" "errors" + "github.com/anyproto/anytype-heart/core/api/internal/object" + "github.com/anyproto/anytype-heart/core/api/pagination" + "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pb/service" + "github.com/anyproto/anytype-heart/pkg/lib/bundle" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) @@ -17,35 +21,94 @@ var ( type Service interface { GetObjectsInList(ctx context.Context, spaceId string, listId string, offset, limit int) ([]*model.Object, int, bool, error) - AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIDs []string) error - RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIDs []string) error - UpdateObjectsInList(ctx context.Context, spaceId string, listId string, objectIDs []string) error + AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIds []string) error + RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIds []string) error + UpdateObjectsInList(ctx context.Context, spaceId string, listId string, objectIds []string) error } type ListService struct { - mw service.ClientCommandsServer + mw service.ClientCommandsServer + objectService *object.ObjectService } -func NewService(mw service.ClientCommandsServer) *ListService { - return &ListService{mw: mw} +func NewService(mw service.ClientCommandsServer, objectService *object.ObjectService) *ListService { + return &ListService{mw: mw, objectService: objectService} } // GetObjectsInList retrieves objects in a list -func (s *ListService) GetObjectsInList(ctx context.Context, spaceId string, listId string, offset, limit int) ([]*model.Object, int, bool, error) { - return nil, 0, false, nil +func (s *ListService) GetObjectsInList(ctx context.Context, spaceId string, listId string, offset, limit int) ([]object.Object, int, bool, error) { + resp := s.mw.ObjectSearchSubscribe(ctx, &pb.RpcObjectSearchSubscribeRequest{ + SpaceId: spaceId, + Limit: int64(limit), // nolint: gosec + Offset: int64(offset), // nolint: gosec + Keys: []string{bundle.RelationKeyId.String()}, + CollectionId: listId, + }) + + if resp.Error.Code != pb.RpcObjectSearchSubscribeResponseError_NULL { + return nil, 0, false, ErrFailedGetObjectsInList + } + + total := int(resp.Counters.Total) + paginatedRecords, hasMore := pagination.Paginate(resp.Records, offset, limit) + + objects := make([]object.Object, 0, len(paginatedRecords)) + for _, record := range paginatedRecords { + object, err := s.objectService.GetObject(ctx, spaceId, record.Fields[bundle.RelationKeyId.String()].GetStringValue()) + if err != nil { + return nil, 0, false, err + } + objects = append(objects, object) + } + + return objects, total, hasMore, nil } // AddObjectsToList adds objects to a list -func (s *ListService) AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIDs []string) error { +func (s *ListService) AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIds []string) error { + resp := s.mw.ObjectCollectionAdd(ctx, &pb.RpcObjectCollectionAddRequest{ + ContextId: listId, + ObjectIds: objectIds, + }) + + if resp.Error.Code != pb.RpcObjectCollectionAddResponseError_NULL { + return ErrFailedAddObjectsToList + } + return nil } // RemoveObjectsFromList removes objects from a list -func (s *ListService) RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIDs []string) error { +func (s *ListService) RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIds []string) error { + resp := s.mw.ObjectCollectionRemove(ctx, &pb.RpcObjectCollectionRemoveRequest{ + ContextId: spaceId, + ObjectIds: objectIds, + }) + + if resp.Error.Code != pb.RpcObjectCollectionRemoveResponseError_NULL { + return ErrFailedRemoveObjectsFromList + } + return nil } // UpdateObjectsInList updates an object in a list -func (s *ListService) UpdateObjectsInList(ctx context.Context, spaceId string, listId string, objectIDs []string) error { +func (s *ListService) UpdateObjectsInList(ctx context.Context, spaceId string, listId string, objectIds []string) error { + resp := s.mw.BlockDataviewObjectOrderUpdate(ctx, &pb.RpcBlockDataviewObjectOrderUpdateRequest{ + ContextId: listId, + BlockId: "dataview", + ObjectOrders: []*model.BlockContentDataviewObjectOrder{ + { + ViewId: "", // TODO: handle viewId + GroupId: "", + ObjectIds: objectIds, + }, + }, + }) + + if resp.Error.Code != pb.RpcBlockDataviewObjectOrderUpdateResponseError_NULL { + return ErrFailedUpdateObjectsInList + } + return nil } diff --git a/core/api/server/server.go b/core/api/server/server.go index 56b312d699..f38dc6c7e7 100644 --- a/core/api/server/server.go +++ b/core/api/server/server.go @@ -35,11 +35,11 @@ func NewServer(accountService account.Service, mw service.ClientCommandsServer) s := &Server{ authService: auth.NewService(mw), exportService: export.NewService(mw), - listService: list.NewService(mw), spaceService: space.NewService(mw), } s.objectService = object.NewService(mw, s.spaceService) + s.listService = list.NewService(mw, s.objectService) s.searchService = search.NewService(mw, s.spaceService, s.objectService) s.engine = s.NewRouter(accountService, mw) s.KeyToToken = make(map[string]string) From 44b1bcc1da15e4b40f87cc92f32534cb24ab9717 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Wed, 12 Feb 2025 15:47:16 +0100 Subject: [PATCH 11/31] GO-4459: Fix v1 route path for lists --- core/api/server/router.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/api/server/router.go b/core/api/server/router.go index f7aad0482d..23d094bbb7 100644 --- a/core/api/server/router.go +++ b/core/api/server/router.go @@ -68,10 +68,10 @@ func (s *Server) NewRouter(accountService account.Service, mw service.ClientComm v1.POST("/spaces/:space_id/objects/:object_id/export/:format", export.GetObjectExportHandler(s.exportService)) // List - v1.GET("/v1/spaces/:space_id/lists/:list_id/objects", list.GetObjectsInListHandler(s.listService)) - v1.POST("/v1/spaces/:space_id/lists/:list_id/objects", list.AddObjectsToListHandler(s.listService)) - v1.DELETE("/v1/spaces/:space_id/lists/:list_id/objects", list.RemoveObjectsFromListHandler(s.listService)) - v1.PATCH("/v1/spaces/:space_id/lists/:list_id/objects", list.UpdateObjectsInListHandler(s.listService)) + v1.GET("/spaces/:space_id/lists/:list_id/objects", list.GetObjectsInListHandler(s.listService)) + v1.POST("/spaces/:space_id/lists/:list_id/objects", list.AddObjectsToListHandler(s.listService)) + v1.DELETE("/spaces/:space_id/lists/:list_id/objects", list.RemoveObjectsFromListHandler(s.listService)) + v1.PATCH("/spaces/:space_id/lists/:list_id/objects", list.UpdateObjectsInListHandler(s.listService)) // Object v1.GET("/spaces/:space_id/objects", object.GetObjectsHandler(s.objectService)) From fd62a2571e39fb5b1c984868cecafb2f83648bf5 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Fri, 14 Feb 2025 16:04:56 +0100 Subject: [PATCH 12/31] GO-4459: Fix ObjectSearchSubscribe panic --- core/api/internal/list/service.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/api/internal/list/service.go b/core/api/internal/list/service.go index 943035c440..42be2f2f37 100644 --- a/core/api/internal/list/service.go +++ b/core/api/internal/list/service.go @@ -45,7 +45,8 @@ func (s *ListService) GetObjectsInList(ctx context.Context, spaceId string, list CollectionId: listId, }) - if resp.Error.Code != pb.RpcObjectSearchSubscribeResponseError_NULL { + // TODO: returned error from ObjectSearchSubscribe is inconsistent with other RPCs: Error is nil instead of Code being NULL + if resp.Error != nil && resp.Error.Code != pb.RpcObjectSearchSubscribeResponseError_NULL { return nil, 0, false, ErrFailedGetObjectsInList } From dcb8a992f1e58bc20b29bfd4fc7a8fecc369c1b7 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Fri, 14 Feb 2025 16:10:48 +0100 Subject: [PATCH 13/31] GO-4459: Remove UpdateObjectsInList handler and route --- core/api/docs/docs.go | 72 ------------------------------- core/api/docs/swagger.json | 72 ------------------------------- core/api/docs/swagger.yaml | 48 --------------------- core/api/internal/list/handler.go | 42 ------------------ core/api/internal/list/service.go | 26 +---------- core/api/server/router.go | 1 - 6 files changed, 1 insertion(+), 260 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index f158831eb6..bc7016d05f 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -1275,78 +1275,6 @@ const docTemplate = `{ } } } - }, - "patch": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "lists" - ], - "summary": "Update object order in list", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "List ID", - "name": "list_id", - "in": "path", - "required": true - }, - { - "description": "List of object IDs", - "name": "objects", - "in": "body", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - ], - "responses": { - "200": { - "description": "Objects updated successfully", - "schema": { - "type": "string" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } } } }, diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index 0d063df110..d8ba3d1463 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -1269,78 +1269,6 @@ } } } - }, - "patch": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "lists" - ], - "summary": "Update object order in list", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "List ID", - "name": "list_id", - "in": "path", - "required": true - }, - { - "description": "List of object IDs", - "name": "objects", - "in": "body", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - ], - "responses": { - "200": { - "description": "Objects updated successfully", - "schema": { - "type": "string" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } } } }, diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 5f31973fac..46c1110f70 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -1423,54 +1423,6 @@ paths: summary: Get objects in list tags: - lists - patch: - consumes: - - application/json - parameters: - - description: Space ID - in: path - name: space_id - required: true - type: string - - description: List ID - in: path - name: list_id - required: true - type: string - - description: List of object IDs - in: body - name: objects - required: true - schema: - items: - type: string - type: array - produces: - - application/json - responses: - "200": - description: Objects updated successfully - schema: - type: string - "400": - description: Bad request - schema: - $ref: '#/definitions/util.ValidationError' - "401": - description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' - "404": - description: Not found - schema: - $ref: '#/definitions/util.NotFoundError' - "500": - description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' - summary: Update object order in list - tags: - - lists post: consumes: - application/json diff --git a/core/api/internal/list/handler.go b/core/api/internal/list/handler.go index e1e7fbd75c..0830390f53 100644 --- a/core/api/internal/list/handler.go +++ b/core/api/internal/list/handler.go @@ -129,45 +129,3 @@ func RemoveObjectsFromListHandler(s *ListService) gin.HandlerFunc { c.JSON(http.StatusOK, "Objects removed successfully") } } - -// UpdateObjectsInListHandler -// -// @Summary Update object order in list -// @Tags lists -// @Accept json -// @Produce json -// @Param space_id path string true "Space ID" -// @Param list_id path string true "List ID" -// @Param objects body []string true "List of object IDs" -// @Success 200 {object} string "Objects updated successfully" -// @Failure 400 {object} util.ValidationError "Bad request" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [patch] -func UpdateObjectsInListHandler(s *ListService) gin.HandlerFunc { - return func(c *gin.Context) { - spaceId := c.Param("space_id") - listId := c.Param("list_id") - - objects := []string{} - if err := c.ShouldBindJSON(&objects); err != nil { - apiErr := util.CodeToAPIError(http.StatusBadRequest, err.Error()) - c.JSON(http.StatusBadRequest, apiErr) - return - } - - err := s.UpdateObjectsInList(c, spaceId, listId, objects) - code := util.MapErrorCode(err, - util.ErrToCode(ErrFailedUpdateObjectsInList, http.StatusInternalServerError), - ) - - if code != http.StatusOK { - apiErr := util.CodeToAPIError(code, err.Error()) - c.JSON(code, apiErr) - return - } - - c.JSON(http.StatusOK, "Objects updated successfully") - } -} diff --git a/core/api/internal/list/service.go b/core/api/internal/list/service.go index 42be2f2f37..625e560506 100644 --- a/core/api/internal/list/service.go +++ b/core/api/internal/list/service.go @@ -9,21 +9,18 @@ import ( "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pb/service" "github.com/anyproto/anytype-heart/pkg/lib/bundle" - "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) var ( ErrFailedGetObjectsInList = errors.New("failed to get objects in list") ErrFailedAddObjectsToList = errors.New("failed to add objects to list") ErrFailedRemoveObjectsFromList = errors.New("failed to remove objects from list") - ErrFailedUpdateObjectsInList = errors.New("failed to update objects in list") ) type Service interface { - GetObjectsInList(ctx context.Context, spaceId string, listId string, offset, limit int) ([]*model.Object, int, bool, error) + GetObjectsInList(ctx context.Context, spaceId string, listId string, offset, limit int) ([]object.Object, int, bool, error) AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIds []string) error RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIds []string) error - UpdateObjectsInList(ctx context.Context, spaceId string, listId string, objectIds []string) error } type ListService struct { @@ -92,24 +89,3 @@ func (s *ListService) RemoveObjectsFromList(ctx context.Context, spaceId string, return nil } - -// UpdateObjectsInList updates an object in a list -func (s *ListService) UpdateObjectsInList(ctx context.Context, spaceId string, listId string, objectIds []string) error { - resp := s.mw.BlockDataviewObjectOrderUpdate(ctx, &pb.RpcBlockDataviewObjectOrderUpdateRequest{ - ContextId: listId, - BlockId: "dataview", - ObjectOrders: []*model.BlockContentDataviewObjectOrder{ - { - ViewId: "", // TODO: handle viewId - GroupId: "", - ObjectIds: objectIds, - }, - }, - }) - - if resp.Error.Code != pb.RpcBlockDataviewObjectOrderUpdateResponseError_NULL { - return ErrFailedUpdateObjectsInList - } - - return nil -} diff --git a/core/api/server/router.go b/core/api/server/router.go index 23d094bbb7..6bc0174119 100644 --- a/core/api/server/router.go +++ b/core/api/server/router.go @@ -71,7 +71,6 @@ func (s *Server) NewRouter(accountService account.Service, mw service.ClientComm v1.GET("/spaces/:space_id/lists/:list_id/objects", list.GetObjectsInListHandler(s.listService)) v1.POST("/spaces/:space_id/lists/:list_id/objects", list.AddObjectsToListHandler(s.listService)) v1.DELETE("/spaces/:space_id/lists/:list_id/objects", list.RemoveObjectsFromListHandler(s.listService)) - v1.PATCH("/spaces/:space_id/lists/:list_id/objects", list.UpdateObjectsInListHandler(s.listService)) // Object v1.GET("/spaces/:space_id/objects", object.GetObjectsHandler(s.objectService)) From cd836a670f17f8979fb7c5af586c6e1a86ae38b2 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Fri, 14 Feb 2025 16:29:28 +0100 Subject: [PATCH 14/31] GO-4459: Return 404 for deleted object --- core/api/internal/object/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index 284a588ad3..3a51a343f4 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -117,7 +117,7 @@ func (s *ObjectService) GetObject(ctx context.Context, spaceId string, objectId ObjectId: objectId, }) - if resp.Error.Code == pb.RpcObjectShowResponseError_NOT_FOUND { + if resp.Error.Code == pb.RpcObjectShowResponseError_NOT_FOUND || resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIsArchived.String()].GetBoolValue() { return Object{}, ErrObjectNotFound } From 40349517bc7a23b3134dd9b7deac48378d707dbe Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Fri, 14 Feb 2025 17:21:47 +0100 Subject: [PATCH 15/31] GO-4459: Refactor data models to include 'object' property and return entire type for object --- core/api/docs/docs.go | 46 ++++---- core/api/docs/swagger.json | 46 ++++---- core/api/docs/swagger.yaml | 36 ++++--- core/api/internal/object/model.go | 13 +-- core/api/internal/object/service.go | 25 ++--- core/api/internal/object/service_test.go | 129 +++++++++++++---------- core/api/internal/search/service_test.go | 72 ++++++------- core/api/internal/space/model.go | 4 +- core/api/internal/space/service.go | 6 +- core/api/util/util.go | 34 ------ 10 files changed, 203 insertions(+), 208 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index bc7016d05f..0c3db26bad 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -1517,6 +1517,11 @@ const docTemplate = `{ "type": "string", "example": "My object" }, + "object": { + "description": "The data model of the object", + "type": "string", + "example": "object" + }, "root_id": { "description": "The id of the object's root", "type": "string", @@ -1534,8 +1539,11 @@ const docTemplate = `{ }, "type": { "description": "The type of the object", - "type": "string", - "example": "Page" + "allOf": [ + { + "$ref": "#/definitions/object.Type" + } + ] } } }, @@ -1570,8 +1578,8 @@ const docTemplate = `{ "type": "string", "example": "My template" }, - "type": { - "description": "The type of the object", + "object": { + "description": "The data model of the object", "type": "string", "example": "template" } @@ -1654,16 +1662,16 @@ const docTemplate = `{ "type": "string", "example": "Page" }, + "object": { + "description": "The data model of the object", + "type": "string", + "example": "type" + }, "recommended_layout": { "description": "The recommended layout of the type", "type": "string", "example": "todo" }, - "type": { - "description": "The type of the object", - "type": "string", - "example": "type" - }, "unique_key": { "description": "The unique key of the type", "type": "string", @@ -1902,6 +1910,11 @@ const docTemplate = `{ "type": "string", "example": "John Doe" }, + "object": { + "description": "The data model of the object", + "type": "string", + "example": "member" + }, "role": { "description": "The role of the member", "type": "string", @@ -1912,11 +1925,6 @@ const docTemplate = `{ "NoPermission" ], "example": "Owner" - }, - "type": { - "description": "The type of the object", - "type": "string", - "example": "member" } } }, @@ -1996,6 +2004,11 @@ const docTemplate = `{ "type": "string", "example": "N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU" }, + "object": { + "description": "The data model of the object", + "type": "string", + "example": "space" + }, "profile_object_id": { "description": "The id of the profile object", "type": "string", @@ -2016,11 +2029,6 @@ const docTemplate = `{ "type": "string", "example": "" }, - "type": { - "description": "The type of the object", - "type": "string", - "example": "space" - }, "widgets_id": { "description": "The id of the widgets", "type": "string", diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index d8ba3d1463..223b833839 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -1511,6 +1511,11 @@ "type": "string", "example": "My object" }, + "object": { + "description": "The data model of the object", + "type": "string", + "example": "object" + }, "root_id": { "description": "The id of the object's root", "type": "string", @@ -1528,8 +1533,11 @@ }, "type": { "description": "The type of the object", - "type": "string", - "example": "Page" + "allOf": [ + { + "$ref": "#/definitions/object.Type" + } + ] } } }, @@ -1564,8 +1572,8 @@ "type": "string", "example": "My template" }, - "type": { - "description": "The type of the object", + "object": { + "description": "The data model of the object", "type": "string", "example": "template" } @@ -1648,16 +1656,16 @@ "type": "string", "example": "Page" }, + "object": { + "description": "The data model of the object", + "type": "string", + "example": "type" + }, "recommended_layout": { "description": "The recommended layout of the type", "type": "string", "example": "todo" }, - "type": { - "description": "The type of the object", - "type": "string", - "example": "type" - }, "unique_key": { "description": "The unique key of the type", "type": "string", @@ -1896,6 +1904,11 @@ "type": "string", "example": "John Doe" }, + "object": { + "description": "The data model of the object", + "type": "string", + "example": "member" + }, "role": { "description": "The role of the member", "type": "string", @@ -1906,11 +1919,6 @@ "NoPermission" ], "example": "Owner" - }, - "type": { - "description": "The type of the object", - "type": "string", - "example": "member" } } }, @@ -1990,6 +1998,11 @@ "type": "string", "example": "N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU" }, + "object": { + "description": "The data model of the object", + "type": "string", + "example": "space" + }, "profile_object_id": { "description": "The id of the profile object", "type": "string", @@ -2010,11 +2023,6 @@ "type": "string", "example": "" }, - "type": { - "description": "The type of the object", - "type": "string", - "example": "space" - }, "widgets_id": { "description": "The id of the widgets", "type": "string", diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 46c1110f70..0dd2b302ac 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -176,6 +176,10 @@ definitions: description: The name of the object example: My object type: string + object: + description: The data model of the object + example: object + type: string root_id: description: The id of the object's root example: bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u @@ -190,9 +194,9 @@ definitions: example: bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1 type: string type: + allOf: + - $ref: '#/definitions/object.Type' description: The type of the object - example: Page - type: string type: object object.ObjectResponse: properties: @@ -215,8 +219,8 @@ definitions: description: The name of the template example: My template type: string - type: - description: The type of the object + object: + description: The data model of the object example: template type: string type: object @@ -279,14 +283,14 @@ definitions: description: The name of the type example: Page type: string + object: + description: The data model of the object + example: type + type: string recommended_layout: description: The recommended layout of the type example: todo type: string - type: - description: The type of the object - example: type - type: string unique_key: description: The unique key of the type example: ot-page @@ -449,6 +453,10 @@ definitions: description: The name of the member example: John Doe type: string + object: + description: The data model of the object + example: member + type: string role: description: The role of the member enum: @@ -458,10 +466,6 @@ definitions: - NoPermission example: Owner type: string - type: - description: The type of the object - example: member - type: string type: object space.MemberResponse: properties: @@ -520,6 +524,10 @@ definitions: description: The network id of the space example: N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU type: string + object: + description: The data model of the object + example: space + type: string profile_object_id: description: The id of the profile object example: bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4 @@ -537,10 +545,6 @@ definitions: description: The timezone of the account example: "" type: string - type: - description: The type of the object - example: space - type: string widgets_id: description: The id of the widgets example: bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva diff --git a/core/api/internal/object/model.go b/core/api/internal/object/model.go index d591214913..5846100ae0 100644 --- a/core/api/internal/object/model.go +++ b/core/api/internal/object/model.go @@ -15,10 +15,11 @@ type ObjectResponse struct { } type Object struct { - Type string `json:"type" example:"Page"` // The type of the object + Object string `json:"object" example:"object"` // The data model of the object Id string `json:"id" example:"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ"` // The id of the object Name string `json:"name" example:"My object"` // The name of the object Icon string `json:"icon" example:"📄"` // The icon of the object + Type Type `json:"type"` // The type of the object Snippet string `json:"snippet" example:"The beginning of the object body..."` // The snippet of the object, especially important for notes as they don't have a name Layout string `json:"layout" example:"basic"` // The layout of the object SpaceId string `json:"space_id" example:"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1"` // The id of the space the object is in @@ -73,7 +74,7 @@ type TypeResponse struct { } type Type struct { - Type string `json:"type" example:"type"` // The type of the object + Object string `json:"object" example:"type"` // The data model of the object Id string `json:"id" example:"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu"` // The id of the type UniqueKey string `json:"unique_key" example:"ot-page"` // The unique key of the type Name string `json:"name" example:"Page"` // The name of the type @@ -86,8 +87,8 @@ type TemplateResponse struct { } type Template struct { - Type string `json:"type" example:"template"` // The type of the object - Id string `json:"id" example:"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge"` // The id of the template - Name string `json:"name" example:"My template"` // The name of the template - Icon string `json:"icon" example:"📄"` // The icon of the template + Object string `json:"object" example:"template"` // The data model of the object + Id string `json:"id" example:"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge"` // The id of the template + Name string `json:"name" example:"My template"` // The name of the template + Icon string `json:"icon" example:"📄"` // The icon of the template } diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index 3a51a343f4..d979245d16 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -126,16 +126,17 @@ func (s *ObjectService) GetObject(ctx context.Context, spaceId string, objectId } icon := util.GetIconFromEmojiOrImage(s.AccountInfo, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconImage.String()].GetStringValue()) - objectTypeName, err := util.ResolveTypeToName(s.mw, spaceId, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyType.String()].GetStringValue()) + objectType, err := s.GetType(ctx, spaceId, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyType.String()].GetStringValue()) if err != nil { return Object{}, err } object := Object{ - Type: objectTypeName, + Object: "object", Id: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyId.String()].GetStringValue(), Name: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue(), Icon: icon, + Type: objectType, Snippet: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySnippet.String()].GetStringValue(), Layout: model.ObjectTypeLayout_name[int32(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLayout.String()].GetNumberValue())], SpaceId: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), @@ -299,7 +300,7 @@ func (s *ObjectService) ListTypes(ctx context.Context, spaceId string, offset in for _, record := range paginatedTypes { types = append(types, Type{ - Type: "type", + Object: "type", Id: record.Fields[bundle.RelationKeyId.String()].GetStringValue(), UniqueKey: record.Fields[bundle.RelationKeyUniqueKey.String()].GetStringValue(), Name: record.Fields[bundle.RelationKeyName.String()].GetStringValue(), @@ -326,7 +327,7 @@ func (s *ObjectService) GetType(ctx context.Context, spaceId string, typeId stri } return Type{ - Type: "type", + Object: "type", Id: typeId, UniqueKey: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyUniqueKey.String()].GetStringValue(), Name: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue(), @@ -399,10 +400,10 @@ func (s *ObjectService) ListTemplates(ctx context.Context, spaceId string, typeI } templates = append(templates, Template{ - Type: "template", - Id: templateId, - Name: templateResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue(), - Icon: templateResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), + Object: "template", + Id: templateId, + Name: templateResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue(), + Icon: templateResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), }) } @@ -425,10 +426,10 @@ func (s *ObjectService) GetTemplate(ctx context.Context, spaceId string, typeId } return Template{ - Type: "template", - Id: templateId, - Name: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue(), - Icon: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), + Object: "template", + Id: templateId, + Name: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue(), + Icon: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), }, nil } diff --git a/core/api/internal/object/service_test.go b/core/api/internal/object/service_test.go index 5ae1f6ba25..f865b96ea7 100644 --- a/core/api/internal/object/service_test.go +++ b/core/api/internal/object/service_test.go @@ -23,7 +23,6 @@ const ( gatewayUrl = "http://localhost:31006" mockedSpaceId = "mocked-space-id" mockedObjectId = "mocked-object-id" - mockedObjectType = "mocked-object-type" mockedNewObjectId = "mocked-new-object-id" mockedObjectName = "mocked-object-name" mockedObjectSnippet = "mocked-object-snippet" @@ -99,7 +98,7 @@ func TestObjectService_ListObjects(t *testing.T) { bundle.RelationKeyName.String(): pbtypes.String(mockedObjectName), bundle.RelationKeySnippet.String(): pbtypes.String(mockedObjectSnippet), bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedObjectIcon), - bundle.RelationKeyType.String(): pbtypes.String(mockedObjectTypeUniqueKey), + bundle.RelationKeyType.String(): pbtypes.String(mockedTypeId), bundle.RelationKeyLayout.String(): pbtypes.Float64(float64(model.ObjectType_basic)), }, }, @@ -122,7 +121,7 @@ func TestObjectService_ListObjects(t *testing.T) { bundle.RelationKeyName.String(): pbtypes.String(mockedObjectName), bundle.RelationKeySnippet.String(): pbtypes.String(mockedObjectSnippet), bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedObjectIcon), - bundle.RelationKeyType.String(): pbtypes.String(mockedObjectTypeUniqueKey), + bundle.RelationKeyType.String(): pbtypes.String(mockedTypeId), bundle.RelationKeyCreatedDate.String(): pbtypes.Float64(888888), bundle.RelationKeyLastModifiedDate.String(): pbtypes.Float64(999999), bundle.RelationKeyLastOpenedDate.String(): pbtypes.Float64(0), @@ -136,25 +135,26 @@ func TestObjectService_ListObjects(t *testing.T) { }).Once() // Mock type resolution - fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ - SpaceId: mockedSpaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - RelationKey: bundle.RelationKeyUniqueKey.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(mockedObjectTypeUniqueKey), - }, - }, - Keys: []string{bundle.RelationKeyName.String()}, - }).Return(&pb.RpcObjectSearchResponse{ - Records: []*types.Struct{ - { - Fields: map[string]*types.Value{ - bundle.RelationKeyName.String(): pbtypes.String(mockedObjectType), + fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedTypeId, + }).Return(&pb.RpcObjectShowResponse{ + ObjectView: &model.ObjectView{ + RootId: mockedTypeId, + Details: []*model.ObjectViewDetailsSet{ + { + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), + bundle.RelationKeyName.String(): pbtypes.String(mockedTypeName), + bundle.RelationKeyUniqueKey.String(): pbtypes.String(mockedTypeUniqueKey), + bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedTypeIcon), + }, + }, }, }, }, - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }).Once() // Mock participant details @@ -190,7 +190,10 @@ func TestObjectService_ListObjects(t *testing.T) { // then require.NoError(t, err) require.Len(t, objects, 1) - require.Equal(t, mockedObjectType, objects[0].Type) + require.Equal(t, mockedTypeId, objects[0].Type.Id) + require.Equal(t, mockedTypeName, objects[0].Type.Name) + require.Equal(t, mockedTypeUniqueKey, objects[0].Type.UniqueKey) + require.Equal(t, mockedTypeIcon, objects[0].Type.Icon) require.Equal(t, mockedObjectId, objects[0].Id) require.Equal(t, mockedObjectName, objects[0].Name) require.Equal(t, mockedObjectSnippet, objects[0].Snippet) @@ -263,7 +266,7 @@ func TestObjectService_GetObject(t *testing.T) { bundle.RelationKeyName.String(): pbtypes.String(mockedObjectName), bundle.RelationKeySnippet.String(): pbtypes.String(mockedObjectSnippet), bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedObjectName), - bundle.RelationKeyType.String(): pbtypes.String(mockedObjectTypeUniqueKey), + bundle.RelationKeyType.String(): pbtypes.String(mockedTypeId), bundle.RelationKeyLastModifiedDate.String(): pbtypes.Float64(999999), bundle.RelationKeyCreatedDate.String(): pbtypes.Float64(888888), bundle.RelationKeyLastOpenedDate.String(): pbtypes.Float64(0), @@ -276,26 +279,27 @@ func TestObjectService_GetObject(t *testing.T) { }, nil).Once() // Mock type resolution - fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ - SpaceId: mockedSpaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - RelationKey: bundle.RelationKeyUniqueKey.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(mockedObjectTypeUniqueKey), - }, - }, - Keys: []string{bundle.RelationKeyName.String()}, - }).Return(&pb.RpcObjectSearchResponse{ - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, - Records: []*types.Struct{ - { - Fields: map[string]*types.Value{ - bundle.RelationKeyName.String(): pbtypes.String(mockedObjectType), + fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedTypeId, + }).Return(&pb.RpcObjectShowResponse{ + ObjectView: &model.ObjectView{ + RootId: mockedTypeId, + Details: []*model.ObjectViewDetailsSet{ + { + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), + bundle.RelationKeyName.String(): pbtypes.String(mockedTypeName), + bundle.RelationKeyUniqueKey.String(): pbtypes.String(mockedTypeUniqueKey), + bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedTypeIcon), + }, + }, }, }, }, - }, nil).Once() + Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, + }).Once() // Mock participant details fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ @@ -329,7 +333,11 @@ func TestObjectService_GetObject(t *testing.T) { // then require.NoError(t, err) - require.Equal(t, mockedObjectType, object.Type) + require.Equal(t, "object", object.Object) + require.Equal(t, mockedTypeId, object.Type.Id) + require.Equal(t, mockedTypeName, object.Type.Name) + require.Equal(t, mockedTypeUniqueKey, object.Type.UniqueKey) + require.Equal(t, mockedTypeIcon, object.Type.Icon) require.Equal(t, mockedObjectId, object.Id) require.Equal(t, mockedObjectName, object.Name) require.Equal(t, mockedObjectSnippet, object.Snippet) @@ -421,7 +429,7 @@ func TestObjectService_CreateObject(t *testing.T) { bundle.RelationKeyId.String(): pbtypes.String(mockedNewObjectId), bundle.RelationKeyName.String(): pbtypes.String(mockedObjectName), bundle.RelationKeyLayout.String(): pbtypes.Float64(float64(model.ObjectType_basic)), - bundle.RelationKeyType.String(): pbtypes.String(mockedObjectTypeUniqueKey), + bundle.RelationKeyType.String(): pbtypes.String(mockedTypeId), bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedObjectIcon), bundle.RelationKeySpaceId.String(): pbtypes.String(mockedSpaceId), }, @@ -433,25 +441,26 @@ func TestObjectService_CreateObject(t *testing.T) { }).Once() // Mock type resolution - fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ - SpaceId: mockedSpaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - RelationKey: bundle.RelationKeyUniqueKey.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(mockedObjectTypeUniqueKey), - }, - }, - Keys: []string{bundle.RelationKeyName.String()}, - }).Return(&pb.RpcObjectSearchResponse{ - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, - Records: []*types.Struct{ - { - Fields: map[string]*types.Value{ - bundle.RelationKeyName.String(): pbtypes.String(mockedObjectType), + fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedTypeId, + }).Return(&pb.RpcObjectShowResponse{ + ObjectView: &model.ObjectView{ + RootId: mockedTypeId, + Details: []*model.ObjectViewDetailsSet{ + { + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), + bundle.RelationKeyName.String(): pbtypes.String(mockedTypeName), + bundle.RelationKeyUniqueKey.String(): pbtypes.String(mockedTypeUniqueKey), + bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedTypeIcon), + }, + }, }, }, }, + Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }).Once() // Mock participant details @@ -491,7 +500,11 @@ func TestObjectService_CreateObject(t *testing.T) { // then require.NoError(t, err) - require.Equal(t, mockedObjectType, object.Type) + require.Equal(t, "object", object.Object) + require.Equal(t, mockedTypeId, object.Type.Id) + require.Equal(t, mockedTypeName, object.Type.Name) + require.Equal(t, mockedTypeUniqueKey, object.Type.UniqueKey) + require.Equal(t, mockedTypeIcon, object.Type.Icon) require.Equal(t, mockedNewObjectId, object.Id) require.Equal(t, mockedObjectName, object.Name) require.Equal(t, mockedObjectIcon, object.Icon) @@ -749,7 +762,7 @@ func TestObjectService_GetTemplate(t *testing.T) { }).Once() // when - template, err := fx.GetTemplate(ctx, mockedSpaceId, mockedObjectType, mockedTemplateId) + template, err := fx.GetTemplate(ctx, mockedSpaceId, mockedTypeId, mockedTemplateId) // then require.NoError(t, err) diff --git a/core/api/internal/search/service_test.go b/core/api/internal/search/service_test.go index 1f248690f3..49e4567abb 100644 --- a/core/api/internal/search/service_test.go +++ b/core/api/internal/search/service_test.go @@ -35,7 +35,6 @@ const ( mockedTagId2 = "mocked-tag-id-2" mockedTagValue2 = "mocked-tag-value-2" mockedTagColor2 = "mocked-tag-color-2" - mockedObjectTypeName = "mocked-object-type-name" mockedParticipantName = "mocked-participant-name" mockedParticipantIcon = "mocked-participant-icon" mockedParticipantImage = "mocked-participant-image" @@ -282,26 +281,23 @@ func TestSearchService_GlobalSearch(t *testing.T) { }, nil).Once() // Mock type resolution - fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ - SpaceId: mockedSpaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - Operator: model.BlockContentDataviewFilter_No, - RelationKey: bundle.RelationKeyId.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(mockedType), - }, - }, - Keys: []string{bundle.RelationKeyName.String()}, - }).Return(&pb.RpcObjectSearchResponse{ - Records: []*types.Struct{ - { - Fields: map[string]*types.Value{ - bundle.RelationKeyName.String(): pbtypes.String(mockedObjectTypeName), + fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedType, + }).Return(&pb.RpcObjectShowResponse{ + ObjectView: &model.ObjectView{ + RootId: mockedType, + Details: []*model.ObjectViewDetailsSet{ + { + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedType), + }, + }, }, }, }, - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }).Once() // Mock participant details @@ -346,10 +342,10 @@ func TestSearchService_GlobalSearch(t *testing.T) { // then require.NoError(t, err) require.Len(t, objects, 1) - require.Equal(t, mockedObjectTypeName, objects[0].Type) - require.Equal(t, mockedSpaceId, objects[0].SpaceId) - require.Equal(t, mockedObjectName, objects[0].Name) require.Equal(t, mockedObjectId, objects[0].Id) + require.Equal(t, mockedObjectName, objects[0].Name) + require.Equal(t, mockedType, objects[0].Type.Id) + require.Equal(t, mockedSpaceId, objects[0].SpaceId) require.Equal(t, model.ObjectTypeLayout_name[int32(model.ObjectType_basic)], objects[0].Layout) require.Equal(t, "🌐", objects[0].Icon) require.Equal(t, "This is a sample text block", objects[0].Blocks[2].Text.Text) @@ -494,26 +490,23 @@ func TestSearchService_Search(t *testing.T) { }).Once() // Mock type resolution - fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ - SpaceId: mockedSpaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - Operator: model.BlockContentDataviewFilter_No, - RelationKey: bundle.RelationKeyId.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(mockedType), - }, - }, - Keys: []string{bundle.RelationKeyName.String()}, - }).Return(&pb.RpcObjectSearchResponse{ - Records: []*types.Struct{ - { - Fields: map[string]*types.Value{ - bundle.RelationKeyName.String(): pbtypes.String(mockedObjectTypeName), + fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedType, + }).Return(&pb.RpcObjectShowResponse{ + ObjectView: &model.ObjectView{ + RootId: mockedType, + Details: []*model.ObjectViewDetailsSet{ + { + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedType), + }, + }, }, }, }, - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }).Once() // Mock participant details @@ -546,8 +539,9 @@ func TestSearchService_Search(t *testing.T) { // then require.NoError(t, err) require.Len(t, objects, 1) - require.Equal(t, mockedObjectName, objects[0].Name) require.Equal(t, mockedObjectId, objects[0].Id) + require.Equal(t, mockedObjectName, objects[0].Name) + require.Equal(t, mockedType, objects[0].Type.Id) require.Equal(t, mockedSpaceId, objects[0].SpaceId) require.Equal(t, model.ObjectTypeLayout_name[int32(model.ObjectType_basic)], objects[0].Layout) diff --git a/core/api/internal/space/model.go b/core/api/internal/space/model.go index 6805de3ccb..16ebe1fb5b 100644 --- a/core/api/internal/space/model.go +++ b/core/api/internal/space/model.go @@ -9,7 +9,7 @@ type CreateSpaceRequest struct { } type Space struct { - Type string `json:"type" example:"space"` // The type of the object + Object string `json:"object" example:"space"` // The data model of the object Id string `json:"id" example:"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1"` // The id of the space Name string `json:"name" example:"My Space"` // The name of the space Icon string `json:"icon" example:"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay"` // The icon of the space @@ -35,7 +35,7 @@ type MemberResponse struct { } type Member struct { - Type string `json:"type" example:"member"` // The type of the object + Object string `json:"object" example:"member"` // The data model of the object Id string `json:"id" example:"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ"` // The profile object id of the member Name string `json:"name" example:"John Doe"` // The name of the member Icon string `json:"icon" example:"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100"` // The icon of the member diff --git a/core/api/internal/space/service.go b/core/api/internal/space/service.go index eb83f636c7..1b36244e0b 100644 --- a/core/api/internal/space/service.go +++ b/core/api/internal/space/service.go @@ -198,7 +198,7 @@ func (s *SpaceService) ListMembers(ctx context.Context, spaceId string, offset i icon := util.GetIconFromEmojiOrImage(s.AccountInfo, record.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), record.Fields[bundle.RelationKeyIconImage.String()].GetStringValue()) member := Member{ - Type: "member", + Object: "member", Id: record.Fields[bundle.RelationKeyId.String()].GetStringValue(), Name: record.Fields[bundle.RelationKeyName.String()].GetStringValue(), Icon: icon, @@ -239,7 +239,7 @@ func (s *SpaceService) GetMember(ctx context.Context, spaceId string, memberId s icon := util.GetIconFromEmojiOrImage(s.AccountInfo, "", resp.Records[0].Fields[bundle.RelationKeyIconImage.String()].GetStringValue()) return Member{ - Type: "member", + Object: "member", Id: resp.Records[0].Fields[bundle.RelationKeyId.String()].GetStringValue(), Name: resp.Records[0].Fields[bundle.RelationKeyName.String()].GetStringValue(), Icon: icon, @@ -261,7 +261,7 @@ func (s *SpaceService) getWorkspaceInfo(spaceId string, name string, icon string } return Space{ - Type: "space", + Object: "space", Id: spaceId, Name: name, Icon: icon, diff --git a/core/api/util/util.go b/core/api/util/util.go index 6c5a74eb98..c8ce71dec2 100644 --- a/core/api/util/util.go +++ b/core/api/util/util.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "strings" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pb/service" @@ -31,39 +30,6 @@ func GetIconFromEmojiOrImage(accountInfo *model.AccountInfo, iconEmoji string, i return "" } -// ResolveTypeToName resolves the type ID to the name of the type, e.g. "ot-page" to "Page" or "bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu" to "Custom Type" -func ResolveTypeToName(mw service.ClientCommandsServer, spaceId string, typeId string) (typeName string, err error) { - // Can't look up preinstalled types based on relation key, therefore need to use unique key - relKey := bundle.RelationKeyId.String() - if strings.HasPrefix(typeId, "ot-") { - relKey = bundle.RelationKeyUniqueKey.String() - } - - // Call ObjectSearch for object of specified type and return the name - resp := mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ - SpaceId: spaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - Operator: model.BlockContentDataviewFilter_No, - RelationKey: relKey, - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(typeId), - }, - }, - Keys: []string{bundle.RelationKeyName.String()}, - }) - - if resp.Error.Code != pb.RpcObjectSearchResponseError_NULL { - return "", ErrFailedSearchType - } - - if len(resp.Records) == 0 { - return "", ErrorTypeNotFound - } - - return resp.Records[0].Fields[bundle.RelationKeyName.String()].GetStringValue(), nil -} - func ResolveUniqueKeyToTypeId(mw service.ClientCommandsServer, spaceId string, uniqueKey string) (typeId string, err error) { // Call ObjectSearch for type with unique key and return the type's ID resp := mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ From 81cdd2ee884709e0c856cc1d70da1a2488b29d5d Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Fri, 14 Feb 2025 18:44:25 +0100 Subject: [PATCH 16/31] GO-4459: Add relation format to detail entries --- core/api/internal/object/service.go | 29 ++++++++++++++++++++---- core/api/internal/object/service_test.go | 12 +++++----- core/api/internal/search/service_test.go | 6 ++--- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index d979245d16..ab077f4790 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -435,6 +435,7 @@ func (s *ObjectService) GetTemplate(ctx context.Context, spaceId string, typeId // GetDetails returns the list of details from the ObjectShowResponse. func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { + relationFormatMap := s.getRelationFormatMap(resp.ObjectView.RelationLinks) creator := resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyCreator.String()].GetStringValue() lastModifiedBy := resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastModifiedBy.String()].GetStringValue() @@ -462,42 +463,62 @@ func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { { Id: "last_modified_date", Details: map[string]interface{}{ - "last_modified_date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastModifiedDate.String()].GetNumberValue()), + "type": relationFormatMap[bundle.RelationKeyLastModifiedDate.String()], + "date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastModifiedDate.String()].GetNumberValue()), }, }, { Id: "last_modified_by", Details: map[string]interface{}{ + "type": relationFormatMap[bundle.RelationKeyLastModifiedBy.String()], "details": memberLastModifiedBy, }, }, { Id: "created_date", Details: map[string]interface{}{ - "created_date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyCreatedDate.String()].GetNumberValue()), + "type": relationFormatMap[bundle.RelationKeyCreatedDate.String()], + "date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyCreatedDate.String()].GetNumberValue()), }, }, { Id: "created_by", Details: map[string]interface{}{ + "type": relationFormatMap[bundle.RelationKeyCreator.String()], "details": memberCreator, }, }, { Id: "last_opened_date", Details: map[string]interface{}{ - "last_opened_date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastOpenedDate.String()].GetNumberValue()), + "type": relationFormatMap[bundle.RelationKeyLastOpenedDate.String()], + "date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastOpenedDate.String()].GetNumberValue()), }, }, { Id: "tags", Details: map[string]interface{}{ - "tags": s.getTags(resp), + "type": relationFormatMap[bundle.RelationKeyTag.String()], + "multi_select": s.getTags(resp), }, }, } } +// getRelationFormatMapFromResponse returns the map of relation key to relation format from the ObjectShowResponse. +func (s *ObjectService) getRelationFormatMap(relationLinks []*model.RelationLink) map[string]string { + var relationFormatToName = model.RelationFormat_name + relationFormatToName[int32(model.RelationFormat_tag)] = "multi_select" + relationFormatToName[int32(model.RelationFormat_status)] = "select" + + relationFormatMap := map[string]string{} + for _, detail := range relationLinks { + relationFormatMap[detail.Key] = relationFormatToName[int32(detail.Format)] + } + + return relationFormatMap +} + // getTags returns the list of tags from the ObjectShowResponse func (s *ObjectService) getTags(resp *pb.RpcObjectShowResponse) []Tag { tags := []Tag{} diff --git a/core/api/internal/object/service_test.go b/core/api/internal/object/service_test.go index f865b96ea7..976b2f1ef0 100644 --- a/core/api/internal/object/service_test.go +++ b/core/api/internal/object/service_test.go @@ -202,15 +202,15 @@ func TestObjectService_ListObjects(t *testing.T) { for _, detail := range objects[0].Details { if detail.Id == "created_date" { - require.Equal(t, "1970-01-11T06:54:48Z", detail.Details["created_date"]) + require.Equal(t, "1970-01-11T06:54:48Z", detail.Details["date"]) } else if detail.Id == "created_by" { require.Empty(t, detail.Details["created_by"]) } else if detail.Id == "last_modified_date" { - require.Equal(t, "1970-01-12T13:46:39Z", detail.Details["last_modified_date"]) + require.Equal(t, "1970-01-12T13:46:39Z", detail.Details["date"]) } else if detail.Id == "last_modified_by" { require.Empty(t, detail.Details["last_modified_by"]) } else if detail.Id == "last_opened_date" { - require.Equal(t, "1970-01-01T00:00:00Z", detail.Details["last_opened_date"]) + require.Equal(t, "1970-01-01T00:00:00Z", detail.Details["date"]) } else if detail.Id == "tags" { require.Empty(t, detail.Details["tags"]) } else { @@ -346,15 +346,15 @@ func TestObjectService_GetObject(t *testing.T) { for _, detail := range object.Details { if detail.Id == "created_date" { - require.Equal(t, "1970-01-11T06:54:48Z", detail.Details["created_date"]) + require.Equal(t, "1970-01-11T06:54:48Z", detail.Details["date"]) } else if detail.Id == "created_by" { require.Empty(t, detail.Details["created_by"]) } else if detail.Id == "last_modified_date" { - require.Equal(t, "1970-01-12T13:46:39Z", detail.Details["last_modified_date"]) + require.Equal(t, "1970-01-12T13:46:39Z", detail.Details["date"]) } else if detail.Id == "last_modified_by" { require.Empty(t, detail.Details["last_modified_by"]) } else if detail.Id == "last_opened_date" { - require.Equal(t, "1970-01-01T00:00:00Z", detail.Details["last_opened_date"]) + require.Equal(t, "1970-01-01T00:00:00Z", detail.Details["date"]) } else if detail.Id == "tags" { require.Empty(t, detail.Details["tags"]) } else { diff --git a/core/api/internal/search/service_test.go b/core/api/internal/search/service_test.go index 49e4567abb..8a55a0b9b6 100644 --- a/core/api/internal/search/service_test.go +++ b/core/api/internal/search/service_test.go @@ -353,9 +353,9 @@ func TestSearchService_GlobalSearch(t *testing.T) { // check details for _, detail := range objects[0].Details { if detail.Id == "created_date" { - require.Equal(t, "1970-01-11T06:54:48Z", detail.Details["created_date"]) + require.Equal(t, "1970-01-11T06:54:48Z", detail.Details["date"]) } else if detail.Id == "last_modified_date" { - require.Equal(t, "1970-01-12T13:46:39Z", detail.Details["last_modified_date"]) + require.Equal(t, "1970-01-12T13:46:39Z", detail.Details["date"]) } else if detail.Id == "created_by" { require.Equal(t, mockedParticipantId, detail.Details["details"].(space.Member).Id) require.Equal(t, mockedParticipantName, detail.Details["details"].(space.Member).Name) @@ -370,7 +370,7 @@ func TestSearchService_GlobalSearch(t *testing.T) { // check tags tags := []object.Tag{} for _, detail := range objects[0].Details { - if tagList, ok := detail.Details["tags"].([]object.Tag); ok { + if tagList, ok := detail.Details["multi_select"].([]object.Tag); ok { for _, tag := range tagList { tags = append(tags, tag) } From 039739fce727f24df17056f8bd747db61eb390d6 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Fri, 14 Feb 2025 19:32:19 +0100 Subject: [PATCH 17/31] GO-4459: Get type directly from details in GetObject and fix detail key for object relation value --- core/api/internal/object/service.go | 55 +++++++++++++++------ core/api/internal/object/service_test.go | 63 ++++++------------------ core/api/internal/search/service_test.go | 43 ++++------------ 3 files changed, 65 insertions(+), 96 deletions(-) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index ab077f4790..10b074bd57 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -3,6 +3,7 @@ package object import ( "context" "errors" + "sync" "time" "github.com/gogo/protobuf/types" @@ -126,23 +127,19 @@ func (s *ObjectService) GetObject(ctx context.Context, spaceId string, objectId } icon := util.GetIconFromEmojiOrImage(s.AccountInfo, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconImage.String()].GetStringValue()) - objectType, err := s.GetType(ctx, spaceId, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyType.String()].GetStringValue()) - if err != nil { - return Object{}, err - } object := Object{ Object: "object", Id: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyId.String()].GetStringValue(), Name: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue(), Icon: icon, - Type: objectType, + Type: s.getTypeFromDetails(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyType.String()].GetStringValue(), resp.ObjectView.Details), Snippet: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySnippet.String()].GetStringValue(), Layout: model.ObjectTypeLayout_name[int32(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLayout.String()].GetNumberValue())], SpaceId: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), RootId: resp.ObjectView.RootId, - Blocks: s.GetBlocks(resp), - Details: s.GetDetails(resp), + Blocks: s.getBlocks(resp), + Details: s.getDetails(resp), } return object, nil @@ -433,8 +430,32 @@ func (s *ObjectService) GetTemplate(ctx context.Context, spaceId string, typeId }, nil } -// GetDetails returns the list of details from the ObjectShowResponse. -func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { +// getTypeFromDetails returns the type from the details of the ObjectShowResponse. +func (s *ObjectService) getTypeFromDetails(typeId string, details []*model.ObjectViewDetailsSet) Type { + var objectTypeDetail *types.Struct + for _, detail := range details { + if detail.Id == typeId { + objectTypeDetail = detail.GetDetails() + break + } + } + + if objectTypeDetail == nil { + return Type{} + } + + return Type{ + Object: "type", + Id: typeId, + UniqueKey: objectTypeDetail.Fields[bundle.RelationKeyUniqueKey.String()].GetStringValue(), + Name: objectTypeDetail.Fields[bundle.RelationKeyName.String()].GetStringValue(), + Icon: objectTypeDetail.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), + RecommendedLayout: model.ObjectTypeLayout_name[int32(objectTypeDetail.Fields[bundle.RelationKeyRecommendedLayout.String()].GetNumberValue())], + } +} + +// getDetails returns the list of details from the ObjectShowResponse. +func (s *ObjectService) getDetails(resp *pb.RpcObjectShowResponse) []Detail { relationFormatMap := s.getRelationFormatMap(resp.ObjectView.RelationLinks) creator := resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyCreator.String()].GetStringValue() lastModifiedBy := resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastModifiedBy.String()].GetStringValue() @@ -470,8 +491,8 @@ func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { { Id: "last_modified_by", Details: map[string]interface{}{ - "type": relationFormatMap[bundle.RelationKeyLastModifiedBy.String()], - "details": memberLastModifiedBy, + "type": relationFormatMap[bundle.RelationKeyLastModifiedBy.String()], + "object": memberLastModifiedBy, }, }, { @@ -484,8 +505,8 @@ func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { { Id: "created_by", Details: map[string]interface{}{ - "type": relationFormatMap[bundle.RelationKeyCreator.String()], - "details": memberCreator, + "type": relationFormatMap[bundle.RelationKeyCreator.String()], + "object": memberCreator, }, }, { @@ -508,6 +529,9 @@ func (s *ObjectService) GetDetails(resp *pb.RpcObjectShowResponse) []Detail { // getRelationFormatMapFromResponse returns the map of relation key to relation format from the ObjectShowResponse. func (s *ObjectService) getRelationFormatMap(relationLinks []*model.RelationLink) map[string]string { var relationFormatToName = model.RelationFormat_name + var mu sync.Mutex + + mu.Lock() relationFormatToName[int32(model.RelationFormat_tag)] = "multi_select" relationFormatToName[int32(model.RelationFormat_status)] = "select" @@ -515,6 +539,7 @@ func (s *ObjectService) getRelationFormatMap(relationLinks []*model.RelationLink for _, detail := range relationLinks { relationFormatMap[detail.Key] = relationFormatToName[int32(detail.Format)] } + mu.Unlock() return relationFormatMap } @@ -544,8 +569,8 @@ func (s *ObjectService) getTags(resp *pb.RpcObjectShowResponse) []Tag { return tags } -// GetBlocks returns the list of blocks from the ObjectShowResponse. -func (s *ObjectService) GetBlocks(resp *pb.RpcObjectShowResponse) []Block { +// getBlocks returns the list of blocks from the ObjectShowResponse. +func (s *ObjectService) getBlocks(resp *pb.RpcObjectShowResponse) []Block { blocks := []Block{} for _, block := range resp.ObjectView.Blocks { diff --git a/core/api/internal/object/service_test.go b/core/api/internal/object/service_test.go index 976b2f1ef0..ed40c5b5ef 100644 --- a/core/api/internal/object/service_test.go +++ b/core/api/internal/object/service_test.go @@ -115,6 +115,7 @@ func TestObjectService_ListObjects(t *testing.T) { RootId: mockedObjectId, Details: []*model.ObjectViewDetailsSet{ { + Id: mockedObjectId, Details: &types.Struct{ Fields: map[string]*types.Value{ bundle.RelationKeyId.String(): pbtypes.String(mockedObjectId), @@ -129,20 +130,8 @@ func TestObjectService_ListObjects(t *testing.T) { }, }, }, - }, - }, - Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, - }).Once() - - // Mock type resolution - fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ - SpaceId: mockedSpaceId, - ObjectId: mockedTypeId, - }).Return(&pb.RpcObjectShowResponse{ - ObjectView: &model.ObjectView{ - RootId: mockedTypeId, - Details: []*model.ObjectViewDetailsSet{ { + Id: mockedTypeId, Details: &types.Struct{ Fields: map[string]*types.Value{ bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), @@ -260,6 +249,7 @@ func TestObjectService_GetObject(t *testing.T) { RootId: mockedObjectId, Details: []*model.ObjectViewDetailsSet{ { + Id: mockedObjectId, Details: &types.Struct{ Fields: map[string]*types.Value{ bundle.RelationKeyId.String(): pbtypes.String(mockedObjectId), @@ -274,32 +264,20 @@ func TestObjectService_GetObject(t *testing.T) { }, }, }, - }, - }, - }, nil).Once() - - // Mock type resolution - fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ - SpaceId: mockedSpaceId, - ObjectId: mockedTypeId, - }).Return(&pb.RpcObjectShowResponse{ - ObjectView: &model.ObjectView{ - RootId: mockedTypeId, - Details: []*model.ObjectViewDetailsSet{ - { - Details: &types.Struct{ - Fields: map[string]*types.Value{ - bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), - bundle.RelationKeyName.String(): pbtypes.String(mockedTypeName), - bundle.RelationKeyUniqueKey.String(): pbtypes.String(mockedTypeUniqueKey), - bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedTypeIcon), + { + Id: mockedTypeId, + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), + bundle.RelationKeyName.String(): pbtypes.String(mockedTypeName), + bundle.RelationKeyUniqueKey.String(): pbtypes.String(mockedTypeUniqueKey), + bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedTypeIcon), + }, }, }, }, }, - }, - Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, - }).Once() + }, nil).Once() // Mock participant details fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ @@ -424,6 +402,7 @@ func TestObjectService_CreateObject(t *testing.T) { RootId: mockedNewObjectId, Details: []*model.ObjectViewDetailsSet{ { + Id: mockedNewObjectId, Details: &types.Struct{ Fields: map[string]*types.Value{ bundle.RelationKeyId.String(): pbtypes.String(mockedNewObjectId), @@ -435,20 +414,8 @@ func TestObjectService_CreateObject(t *testing.T) { }, }, }, - }, - }, - Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, - }).Once() - - // Mock type resolution - fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ - SpaceId: mockedSpaceId, - ObjectId: mockedTypeId, - }).Return(&pb.RpcObjectShowResponse{ - ObjectView: &model.ObjectView{ - RootId: mockedTypeId, - Details: []*model.ObjectViewDetailsSet{ { + Id: mockedTypeId, Details: &types.Struct{ Fields: map[string]*types.Value{ bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), diff --git a/core/api/internal/search/service_test.go b/core/api/internal/search/service_test.go index 8a55a0b9b6..233b6ee4f3 100644 --- a/core/api/internal/search/service_test.go +++ b/core/api/internal/search/service_test.go @@ -275,20 +275,8 @@ func TestSearchService_GlobalSearch(t *testing.T) { }, }, }, - }, - }, - Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, - }, nil).Once() - - // Mock type resolution - fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ - SpaceId: mockedSpaceId, - ObjectId: mockedType, - }).Return(&pb.RpcObjectShowResponse{ - ObjectView: &model.ObjectView{ - RootId: mockedType, - Details: []*model.ObjectViewDetailsSet{ { + Id: mockedType, Details: &types.Struct{ Fields: map[string]*types.Value{ bundle.RelationKeyId.String(): pbtypes.String(mockedType), @@ -298,7 +286,7 @@ func TestSearchService_GlobalSearch(t *testing.T) { }, }, Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, - }).Once() + }, nil).Once() // Mock participant details fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ @@ -357,13 +345,13 @@ func TestSearchService_GlobalSearch(t *testing.T) { } else if detail.Id == "last_modified_date" { require.Equal(t, "1970-01-12T13:46:39Z", detail.Details["date"]) } else if detail.Id == "created_by" { - require.Equal(t, mockedParticipantId, detail.Details["details"].(space.Member).Id) - require.Equal(t, mockedParticipantName, detail.Details["details"].(space.Member).Name) - require.Equal(t, gatewayUrl+"/image/"+mockedParticipantImage, detail.Details["details"].(space.Member).Icon) - require.Equal(t, mockedParticipantIdentity, detail.Details["details"].(space.Member).Identity) - require.Equal(t, mockedParticipantGlobalName, detail.Details["details"].(space.Member).GlobalName) + require.Equal(t, mockedParticipantId, detail.Details["object"].(space.Member).Id) + require.Equal(t, mockedParticipantName, detail.Details["object"].(space.Member).Name) + require.Equal(t, gatewayUrl+"/image/"+mockedParticipantImage, detail.Details["object"].(space.Member).Icon) + require.Equal(t, mockedParticipantIdentity, detail.Details["object"].(space.Member).Identity) + require.Equal(t, mockedParticipantGlobalName, detail.Details["object"].(space.Member).GlobalName) } else if detail.Id == "last_modified_by" { - require.Equal(t, mockedParticipantId, detail.Details["details"].(space.Member).Id) + require.Equal(t, mockedParticipantId, detail.Details["object"].(space.Member).Id) } } @@ -473,6 +461,7 @@ func TestSearchService_Search(t *testing.T) { RootId: mockedRootId, Details: []*model.ObjectViewDetailsSet{ { + Id: mockedRootId, Details: &types.Struct{ Fields: map[string]*types.Value{ bundle.RelationKeyId.String(): pbtypes.String(mockedObjectId), @@ -484,20 +473,8 @@ func TestSearchService_Search(t *testing.T) { }, }, }, - }, - }, - Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, - }).Once() - - // Mock type resolution - fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ - SpaceId: mockedSpaceId, - ObjectId: mockedType, - }).Return(&pb.RpcObjectShowResponse{ - ObjectView: &model.ObjectView{ - RootId: mockedType, - Details: []*model.ObjectViewDetailsSet{ { + Id: mockedType, Details: &types.Struct{ Fields: map[string]*types.Value{ bundle.RelationKeyId.String(): pbtypes.String(mockedType), From 280d63ccd00c1306ef910571f74f0654ab05f163 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sat, 15 Feb 2025 13:29:43 +0100 Subject: [PATCH 18/31] GO-4459: Return custom relations in details of object response --- core/api/internal/object/model.go | 20 +-- core/api/internal/object/service.go | 149 ++++++++++++++--------- core/api/internal/object/service_test.go | 135 ++++++++++---------- core/api/internal/search/service_test.go | 47 ++++--- core/api/util/util.go | 26 ++++ 5 files changed, 225 insertions(+), 152 deletions(-) diff --git a/core/api/internal/object/model.go b/core/api/internal/object/model.go index 5846100ae0..b83284b3ce 100644 --- a/core/api/internal/object/model.go +++ b/core/api/internal/object/model.go @@ -29,13 +29,14 @@ type Object struct { } type Block struct { - Id string `json:"id" example:"64394517de52ad5acb89c66c"` // The id of the block - ChildrenIds []string `json:"children_ids" example:"['6797ce8ecda913cde14b02dc']"` // The ids of the block's children - BackgroundColor string `json:"background_color" example:"red"` // The background color of the block - Align string `json:"align" enums:"AlignLeft,AlignCenter,AlignRight,AlignJustify" example:"AlignLeft"` // The alignment of the block - VerticalAlign string `json:"vertical_align" enums:"VerticalAlignTop,VerticalAlignMiddle,VerticalAlignBottom" example:"VerticalAlignTop"` // The vertical alignment of the block - Text *Text `json:"text,omitempty"` // The text of the block, if applicable - File *File `json:"file,omitempty"` // The file of the block, if applicable + Id string `json:"id" example:"64394517de52ad5acb89c66c"` // The id of the block + ChildrenIds []string `json:"children_ids" example:"['6797ce8ecda913cde14b02dc']"` // The ids of the block's children + BackgroundColor string `json:"background_color" example:"red"` // The background color of the block + Align string `json:"align" enums:"AlignLeft,AlignCenter,AlignRight,AlignJustify" example:"AlignLeft"` // The alignment of the block + VerticalAlign string `json:"vertical_align" enums:"VerticalAlignTop,VerticalAlignMiddle,VerticalAlignBottom" example:"VerticalAlignTop"` // The vertical alignment of the block + Text *Text `json:"text,omitempty"` // The text of the block, if applicable + File *File `json:"file,omitempty"` // The file of the block, if applicable + Relation *Relation `json:"relation,omitempty"` // The relation of the block, if applicable } type Text struct { @@ -58,6 +59,11 @@ type File struct { Style string `json:"style"` // The style of the file } +// TODO: fill in the relation struct +type Relation struct { + Id string +} + type Detail struct { Id string `json:"id" enums:"last_modified_date,last_modified_by,created_date,created_by,last_opened_date,tags" example:"last_modified_date"` // The id of the detail Details map[string]interface{} `json:"details"` // The details diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index 10b074bd57..2ec4ba64b4 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -7,10 +7,12 @@ import ( "time" "github.com/gogo/protobuf/types" + "github.com/iancoleman/strcase" "github.com/anyproto/anytype-heart/core/api/internal/space" "github.com/anyproto/anytype-heart/core/api/pagination" "github.com/anyproto/anytype-heart/core/api/util" + "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pb/service" "github.com/anyproto/anytype-heart/pkg/lib/bundle" @@ -454,75 +456,94 @@ func (s *ObjectService) getTypeFromDetails(typeId string, details []*model.Objec } } -// getDetails returns the list of details from the ObjectShowResponse. +// getDetails returns a list of details by iterating over all relations found in the RelationLinks and mapping their format and value. func (s *ObjectService) getDetails(resp *pb.RpcObjectShowResponse) []Detail { relationFormatMap := s.getRelationFormatMap(resp.ObjectView.RelationLinks) - creator := resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyCreator.String()].GetStringValue() - lastModifiedBy := resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastModifiedBy.String()].GetStringValue() - - var creatorId, lastModifiedById string - for _, detail := range resp.ObjectView.Details { - if detail.Id == creator { - creatorId = detail.Id - } - if detail.Id == lastModifiedBy { - lastModifiedById = detail.Id + linkedRelations := resp.ObjectView.RelationLinks + primaryDetailFields := resp.ObjectView.Details[0].Details.Fields + + var details []Detail + for _, r := range linkedRelations { + if val, ok := primaryDetailFields[r.Key]; ok { + relName := s.getRelationName(r.Key, resp) + format := relationFormatMap[r.Key] + details = append(details, Detail{ + Id: strcase.ToSnake(relName), + Details: map[string]interface{}{ + "name": relName, + "type": format, + format: s.convertValue(val, format, r.Key, resp.ObjectView.Details), + }, + }) } } + return details +} - memberLastModifiedBy, err := s.spaceService.GetMember(context.Background(), resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), lastModifiedById) +// getRelationName returns the relation name from the RelationKey or the resolved relation name. +func (s *ObjectService) getRelationName(key string, resp *pb.RpcObjectShowResponse) string { + relation, err := bundle.GetRelation(domain.RelationKey(key)) if err != nil { - memberLastModifiedBy = space.Member{} + relation, err = util.ResolveRelationKeyToRelationName(s.mw, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), key) + if err != nil { + return key + } } - memberCreator, err := s.spaceService.GetMember(context.Background(), resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), creatorId) - if err != nil { - memberCreator = space.Member{} + // custom relation names + if key == bundle.RelationKeyCreator.String() { + return "Created By" + } else if key == bundle.RelationKeyCreatedDate.String() { + return "Created Date" } - return []Detail{ - { - Id: "last_modified_date", - Details: map[string]interface{}{ - "type": relationFormatMap[bundle.RelationKeyLastModifiedDate.String()], - "date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastModifiedDate.String()].GetNumberValue()), - }, - }, - { - Id: "last_modified_by", - Details: map[string]interface{}{ - "type": relationFormatMap[bundle.RelationKeyLastModifiedBy.String()], - "object": memberLastModifiedBy, - }, - }, - { - Id: "created_date", - Details: map[string]interface{}{ - "type": relationFormatMap[bundle.RelationKeyCreatedDate.String()], - "date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyCreatedDate.String()].GetNumberValue()), - }, - }, - { - Id: "created_by", - Details: map[string]interface{}{ - "type": relationFormatMap[bundle.RelationKeyCreator.String()], - "object": memberCreator, - }, - }, - { - Id: "last_opened_date", - Details: map[string]interface{}{ - "type": relationFormatMap[bundle.RelationKeyLastOpenedDate.String()], - "date": PosixToISO8601(resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyLastOpenedDate.String()].GetNumberValue()), - }, - }, - { - Id: "tags", - Details: map[string]interface{}{ - "type": relationFormatMap[bundle.RelationKeyTag.String()], - "multi_select": s.getTags(resp), - }, - }, + return relation.Name +} + +// convertValue converts a protobuf types.Value into a native Go value. +func (s *ObjectService) convertValue(value *types.Value, format string, key string, details []*model.ObjectViewDetailsSet) interface{} { + switch kind := value.Kind.(type) { + case *types.Value_NullValue: + return nil + case *types.Value_NumberValue: + if format == "date" { + return PosixToISO8601(kind.NumberValue) + } + return kind.NumberValue + case *types.Value_StringValue: + if key == bundle.RelationKeyCreator.String() || key == bundle.RelationKeyLastModifiedBy.String() { + member, err := s.spaceService.GetMember(context.Background(), details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), kind.StringValue) + if err != nil { + return nil + } + return member + } + return kind.StringValue + case *types.Value_BoolValue: + return kind.BoolValue + case *types.Value_StructValue: + m := make(map[string]interface{}) + for k, v := range kind.StructValue.Fields { + m[k] = s.convertValue(v, format, key, details) + } + return m + case *types.Value_ListValue: + var list []interface{} + for _, v := range kind.ListValue.Values { + list = append(list, s.convertValue(v, format, key, details)) + } + + if format == "select" || format == "multi_select" { + return s.getTags(&pb.RpcObjectShowResponse{ + ObjectView: &model.ObjectView{ + Details: details, + }, + }) + } + + return list + default: + return nil } } @@ -532,6 +553,8 @@ func (s *ObjectService) getRelationFormatMap(relationLinks []*model.RelationLink var mu sync.Mutex mu.Lock() + relationFormatToName[int32(model.RelationFormat_longtext)] = "text" + relationFormatToName[int32(model.RelationFormat_shorttext)] = "text" relationFormatToName[int32(model.RelationFormat_tag)] = "multi_select" relationFormatToName[int32(model.RelationFormat_status)] = "select" @@ -576,6 +599,7 @@ func (s *ObjectService) getBlocks(resp *pb.RpcObjectShowResponse) []Block { for _, block := range resp.ObjectView.Blocks { var text *Text var file *File + var relation *Relation switch content := block.Content.(type) { case *model.BlockContentOfText: @@ -598,8 +622,12 @@ func (s *ObjectService) getBlocks(resp *pb.RpcObjectShowResponse) []Block { State: model.BlockContentFileState_name[int32(content.File.State)], Style: model.BlockContentFileStyle_name[int32(content.File.Style)], } - // TODO: other content types? + case *model.BlockContentOfRelation: + relation = &Relation{ + Id: content.Relation.Key, + } } + // TODO: other content types? blocks = append(blocks, Block{ Id: block.Id, @@ -609,6 +637,7 @@ func (s *ObjectService) getBlocks(resp *pb.RpcObjectShowResponse) []Block { VerticalAlign: model.BlockVerticalAlign_name[int32(block.VerticalAlign)], Text: text, File: file, + Relation: relation, }) } diff --git a/core/api/internal/object/service_test.go b/core/api/internal/object/service_test.go index ed40c5b5ef..447f2f6913 100644 --- a/core/api/internal/object/service_test.go +++ b/core/api/internal/object/service_test.go @@ -27,6 +27,7 @@ const ( mockedObjectName = "mocked-object-name" mockedObjectSnippet = "mocked-object-snippet" mockedObjectIcon = "🔍" + mockedParticipantId = "mocked-participant-id" mockedObjectTypeUniqueKey = "ot-page" mockedTypeId = "mocked-type-id" mockedTypeName = "mocked-type-name" @@ -122,11 +123,21 @@ func TestObjectService_ListObjects(t *testing.T) { bundle.RelationKeyName.String(): pbtypes.String(mockedObjectName), bundle.RelationKeySnippet.String(): pbtypes.String(mockedObjectSnippet), bundle.RelationKeyIconEmoji.String(): pbtypes.String(mockedObjectIcon), - bundle.RelationKeyType.String(): pbtypes.String(mockedTypeId), bundle.RelationKeyCreatedDate.String(): pbtypes.Float64(888888), + bundle.RelationKeyLastModifiedBy.String(): pbtypes.String(mockedParticipantId), bundle.RelationKeyLastModifiedDate.String(): pbtypes.Float64(999999), + bundle.RelationKeyCreator.String(): pbtypes.String(mockedParticipantId), bundle.RelationKeyLastOpenedDate.String(): pbtypes.Float64(0), bundle.RelationKeySpaceId.String(): pbtypes.String(mockedSpaceId), + bundle.RelationKeyType.String(): pbtypes.String(mockedTypeId), + }, + }, + }, + { + Id: mockedParticipantId, + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedParticipantId), }, }, }, @@ -142,6 +153,32 @@ func TestObjectService_ListObjects(t *testing.T) { }, }, }, + RelationLinks: []*model.RelationLink{ + { + Key: bundle.RelationKeyLastModifiedDate.String(), + Format: model.RelationFormat_date, + }, + { + Key: bundle.RelationKeyLastModifiedBy.String(), + Format: model.RelationFormat_object, + }, + { + Key: bundle.RelationKeyCreatedDate.String(), + Format: model.RelationFormat_date, + }, + { + Key: bundle.RelationKeyCreator.String(), + Format: model.RelationFormat_object, + }, + { + Key: bundle.RelationKeyLastOpenedDate.String(), + Format: model.RelationFormat_date, + }, + { + Key: bundle.RelationKeyTag.String(), + Format: model.RelationFormat_tag, + }, + }, }, Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }).Once() @@ -154,7 +191,7 @@ func TestObjectService_ListObjects(t *testing.T) { Operator: model.BlockContentDataviewFilter_No, RelationKey: bundle.RelationKeyId.String(), Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(""), + Value: pbtypes.String(mockedParticipantId), }, }, Keys: []string{ @@ -169,7 +206,11 @@ func TestObjectService_ListObjects(t *testing.T) { }).Return(&pb.RpcObjectSearchResponse{ Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, Records: []*types.Struct{ - {}, + { + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedParticipantId), + }, + }, }, }).Twice() @@ -187,17 +228,17 @@ func TestObjectService_ListObjects(t *testing.T) { require.Equal(t, mockedObjectName, objects[0].Name) require.Equal(t, mockedObjectSnippet, objects[0].Snippet) require.Equal(t, mockedObjectIcon, objects[0].Icon) - require.Equal(t, 6, len(objects[0].Details)) + require.Equal(t, 5, len(objects[0].Details)) for _, detail := range objects[0].Details { if detail.Id == "created_date" { require.Equal(t, "1970-01-11T06:54:48Z", detail.Details["date"]) } else if detail.Id == "created_by" { - require.Empty(t, detail.Details["created_by"]) + require.Equal(t, mockedParticipantId, detail.Details["object"].(space.Member).Id) } else if detail.Id == "last_modified_date" { require.Equal(t, "1970-01-12T13:46:39Z", detail.Details["date"]) } else if detail.Id == "last_modified_by" { - require.Empty(t, detail.Details["last_modified_by"]) + require.Equal(t, mockedParticipantId, detail.Details["object"].(space.Member).Id) } else if detail.Id == "last_opened_date" { require.Equal(t, "1970-01-01T00:00:00Z", detail.Details["date"]) } else if detail.Id == "tags" { @@ -276,36 +317,35 @@ func TestObjectService_GetObject(t *testing.T) { }, }, }, + RelationLinks: []*model.RelationLink{ + { + Key: bundle.RelationKeyLastModifiedDate.String(), + Format: model.RelationFormat_date, + }, + { + Key: bundle.RelationKeyLastModifiedBy.String(), + Format: model.RelationFormat_object, + }, + { + Key: bundle.RelationKeyCreatedDate.String(), + Format: model.RelationFormat_date, + }, + { + Key: bundle.RelationKeyCreator.String(), + Format: model.RelationFormat_object, + }, + { + Key: bundle.RelationKeyLastOpenedDate.String(), + Format: model.RelationFormat_date, + }, + { + Key: bundle.RelationKeyTag.String(), + Format: model.RelationFormat_tag, + }, + }, }, }, nil).Once() - // Mock participant details - fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ - SpaceId: mockedSpaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - Operator: model.BlockContentDataviewFilter_No, - RelationKey: bundle.RelationKeyId.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(""), - }, - }, - Keys: []string{ - bundle.RelationKeyId.String(), - bundle.RelationKeyName.String(), - bundle.RelationKeyIconEmoji.String(), - bundle.RelationKeyIconImage.String(), - bundle.RelationKeyIdentity.String(), - bundle.RelationKeyGlobalName.String(), - bundle.RelationKeyParticipantPermissions.String(), - }, - }).Return(&pb.RpcObjectSearchResponse{ - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, - Records: []*types.Struct{ - {}, - }, - }).Twice() - // when object, err := fx.GetObject(ctx, mockedSpaceId, mockedObjectId) @@ -320,7 +360,7 @@ func TestObjectService_GetObject(t *testing.T) { require.Equal(t, mockedObjectName, object.Name) require.Equal(t, mockedObjectSnippet, object.Snippet) require.Equal(t, mockedObjectName, object.Icon) - require.Equal(t, 6, len(object.Details)) + require.Equal(t, 3, len(object.Details)) for _, detail := range object.Details { if detail.Id == "created_date" { @@ -430,33 +470,6 @@ func TestObjectService_CreateObject(t *testing.T) { Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }).Once() - // Mock participant details - fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ - SpaceId: mockedSpaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - Operator: model.BlockContentDataviewFilter_No, - RelationKey: bundle.RelationKeyId.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(""), - }, - }, - Keys: []string{ - bundle.RelationKeyId.String(), - bundle.RelationKeyName.String(), - bundle.RelationKeyIconEmoji.String(), - bundle.RelationKeyIconImage.String(), - bundle.RelationKeyIdentity.String(), - bundle.RelationKeyGlobalName.String(), - bundle.RelationKeyParticipantPermissions.String(), - }, - }).Return(&pb.RpcObjectSearchResponse{ - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, - Records: []*types.Struct{ - {}, - }, - }).Twice() - // when object, err := fx.CreateObject(ctx, mockedSpaceId, CreateObjectRequest{ Name: mockedObjectName, diff --git a/core/api/internal/search/service_test.go b/core/api/internal/search/service_test.go index 233b6ee4f3..c6d1e023ad 100644 --- a/core/api/internal/search/service_test.go +++ b/core/api/internal/search/service_test.go @@ -284,7 +284,30 @@ func TestSearchService_GlobalSearch(t *testing.T) { }, }, }, + RelationLinks: []*model.RelationLink{ + { + Key: bundle.RelationKeyLastModifiedDate.String(), + Format: model.RelationFormat_date, + }, + { + Key: bundle.RelationKeyLastModifiedBy.String(), + Format: model.RelationFormat_object, + }, + { + Key: bundle.RelationKeyCreatedDate.String(), + Format: model.RelationFormat_date, + }, + { + Key: bundle.RelationKeyCreator.String(), + Format: model.RelationFormat_object, + }, + { + Key: bundle.RelationKeyTag.String(), + Format: model.RelationFormat_tag, + }, + }, }, + Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }, nil).Once() @@ -486,30 +509,6 @@ func TestSearchService_Search(t *testing.T) { Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }).Once() - // Mock participant details - fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ - SpaceId: mockedSpaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - Operator: model.BlockContentDataviewFilter_No, - RelationKey: bundle.RelationKeyId.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(""), - }, - }, - Keys: []string{bundle.RelationKeyId.String(), - bundle.RelationKeyName.String(), - bundle.RelationKeyIconEmoji.String(), - bundle.RelationKeyIconImage.String(), - bundle.RelationKeyIdentity.String(), - bundle.RelationKeyGlobalName.String(), - bundle.RelationKeyParticipantPermissions.String(), - }, - }).Return(&pb.RpcObjectSearchResponse{ - Records: []*types.Struct{}, - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, - }).Twice() - // when objects, total, hasMore, err := fx.Search(ctx, mockedSpaceId, SearchRequest{Query: mockedSearchTerm, Types: []string{}, Sort: SortOptions{Direction: "desc", Timestamp: "last_modified_date"}}, offset, limit) diff --git a/core/api/util/util.go b/core/api/util/util.go index c8ce71dec2..db6e3e427f 100644 --- a/core/api/util/util.go +++ b/core/api/util/util.go @@ -54,3 +54,29 @@ func ResolveUniqueKeyToTypeId(mw service.ClientCommandsServer, spaceId string, u return resp.Records[0].Fields[bundle.RelationKeyId.String()].GetStringValue(), nil } + +func ResolveRelationKeyToRelationName(mw service.ClientCommandsServer, spaceId string, relationKey string) (relation *model.Relation, err error) { + resp := mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ + SpaceId: spaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyRelationKey.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.String(relationKey), + }, + }, + Keys: []string{bundle.RelationKeyId.String()}, + }) + + if resp.Error.Code != pb.RpcObjectSearchResponseError_NULL { + return &model.Relation{}, ErrFailedSearchType + } + + if len(resp.Records) == 0 { + return &model.Relation{}, ErrorTypeNotFound + } + + return &model.Relation{ + Name: resp.Records[0].Fields[bundle.RelationKeyName.String()].GetStringValue(), + }, nil +} From 820a894bf135b5fb815c8903623109c93236b888 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sat, 15 Feb 2025 20:07:13 +0100 Subject: [PATCH 19/31] GO-4459: Add exclusion of system relations in object details --- core/api/internal/object/service.go | 94 +++++++++++++++++++---------- core/api/util/util.go | 8 ++- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index 2ec4ba64b4..0079b90952 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -3,8 +3,6 @@ package object import ( "context" "errors" - "sync" - "time" "github.com/gogo/protobuf/types" "github.com/iancoleman/strcase" @@ -462,15 +460,58 @@ func (s *ObjectService) getDetails(resp *pb.RpcObjectShowResponse) []Detail { linkedRelations := resp.ObjectView.RelationLinks primaryDetailFields := resp.ObjectView.Details[0].Details.Fields + // system relations to be excluded + excludeRelations := map[string]bool{ + bundle.RelationKeyId.String(): true, + bundle.RelationKeySpaceId.String(): true, + bundle.RelationKeyName.String(): true, + bundle.RelationKeyIconEmoji.String(): true, + bundle.RelationKeyIconImage.String(): true, + bundle.RelationKeyType.String(): true, + bundle.RelationKeyLayout.String(): true, + bundle.RelationKeyIsFavorite.String(): true, + bundle.RelationKeyIsArchived.String(): true, + bundle.RelationKeyIsDeleted.String(): true, + bundle.RelationKeyIsHidden.String(): true, + bundle.RelationKeyWorkspaceId.String(): true, + bundle.RelationKeyInternalFlags.String(): true, + bundle.RelationKeyRestrictions.String(): true, + bundle.RelationKeyOrigin.String(): true, + bundle.RelationKeySnippet.String(): true, + bundle.RelationKeySyncStatus.String(): true, + bundle.RelationKeySyncError.String(): true, + bundle.RelationKeySyncDate.String(): true, + bundle.RelationKeyCoverId.String(): true, + bundle.RelationKeyCoverType.String(): true, + bundle.RelationKeyCoverScale.String(): true, + bundle.RelationKeyCoverX.String(): true, + bundle.RelationKeyCoverY.String(): true, + bundle.RelationKeyMentions.String(): true, + bundle.RelationKeyOldAnytypeID.String(): true, + bundle.RelationKeySource.String(): true, + bundle.RelationKeySourceFilePath.String(): true, + bundle.RelationKeyImportType.String(): true, + bundle.RelationKeyTargetObjectType.String(): true, + bundle.RelationKeyFeaturedRelations.String(): true, + bundle.RelationKeySetOf.String(): true, + bundle.RelationKeyLinks.String(): true, + bundle.RelationKeyBacklinks.String(): true, + bundle.RelationKeySourceObject.String(): true, + } + var details []Detail for _, r := range linkedRelations { + if _, isExcluded := excludeRelations[r.Key]; isExcluded { + continue + } + if val, ok := primaryDetailFields[r.Key]; ok { - relName := s.getRelationName(r.Key, resp) + id, name := s.getRelation(r.Key, resp) format := relationFormatMap[r.Key] details = append(details, Detail{ - Id: strcase.ToSnake(relName), + Id: id, Details: map[string]interface{}{ - "name": relName, + "name": name, "type": format, format: s.convertValue(val, format, r.Key, resp.ObjectView.Details), }, @@ -480,24 +521,25 @@ func (s *ObjectService) getDetails(resp *pb.RpcObjectShowResponse) []Detail { return details } -// getRelationName returns the relation name from the RelationKey or the resolved relation name. -func (s *ObjectService) getRelationName(key string, resp *pb.RpcObjectShowResponse) string { +// getRelationName returns the relation id and relation name from the ObjectShowResponse. +func (s *ObjectService) getRelation(key string, resp *pb.RpcObjectShowResponse) (id string, name string) { relation, err := bundle.GetRelation(domain.RelationKey(key)) if err != nil { relation, err = util.ResolveRelationKeyToRelationName(s.mw, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), key) if err != nil { - return key + return strcase.ToSnake(key), key } + return key, relation.Name } - // custom relation names + // special cases of relation keys and names if key == bundle.RelationKeyCreator.String() { - return "Created By" + return "created_by", "Created By" } else if key == bundle.RelationKeyCreatedDate.String() { - return "Created Date" + return "created_date", "Created Date" } - return relation.Name + return strcase.ToSnake(key), relation.Name } // convertValue converts a protobuf types.Value into a native Go value. @@ -507,7 +549,7 @@ func (s *ObjectService) convertValue(value *types.Value, format string, key stri return nil case *types.Value_NumberValue: if format == "date" { - return PosixToISO8601(kind.NumberValue) + return util.PosixToISO8601(kind.NumberValue) } return kind.NumberValue case *types.Value_StringValue: @@ -534,11 +576,7 @@ func (s *ObjectService) convertValue(value *types.Value, format string, key stri } if format == "select" || format == "multi_select" { - return s.getTags(&pb.RpcObjectShowResponse{ - ObjectView: &model.ObjectView{ - Details: details, - }, - }) + return s.getTags(key, details) } return list @@ -549,10 +587,10 @@ func (s *ObjectService) convertValue(value *types.Value, format string, key stri // getRelationFormatMapFromResponse returns the map of relation key to relation format from the ObjectShowResponse. func (s *ObjectService) getRelationFormatMap(relationLinks []*model.RelationLink) map[string]string { - var relationFormatToName = model.RelationFormat_name - var mu sync.Mutex - - mu.Lock() + relationFormatToName := make(map[int32]string, len(model.RelationFormat_name)) + for k, v := range model.RelationFormat_name { + relationFormatToName[k] = v + } relationFormatToName[int32(model.RelationFormat_longtext)] = "text" relationFormatToName[int32(model.RelationFormat_shorttext)] = "text" relationFormatToName[int32(model.RelationFormat_tag)] = "multi_select" @@ -562,23 +600,22 @@ func (s *ObjectService) getRelationFormatMap(relationLinks []*model.RelationLink for _, detail := range relationLinks { relationFormatMap[detail.Key] = relationFormatToName[int32(detail.Format)] } - mu.Unlock() return relationFormatMap } // getTags returns the list of tags from the ObjectShowResponse -func (s *ObjectService) getTags(resp *pb.RpcObjectShowResponse) []Tag { +func (s *ObjectService) getTags(key string, details []*model.ObjectViewDetailsSet) []Tag { tags := []Tag{} - tagField, ok := resp.ObjectView.Details[0].Details.Fields["tag"] + tagField, ok := details[0].Details.Fields[key] if !ok || tagField.GetListValue() == nil { return tags } for _, tagId := range tagField.GetListValue().Values { id := tagId.GetStringValue() - for _, detail := range resp.ObjectView.Details { + for _, detail := range details { if detail.Id == id { tags = append(tags, Tag{ Id: id, @@ -643,8 +680,3 @@ func (s *ObjectService) getBlocks(resp *pb.RpcObjectShowResponse) []Block { return blocks } - -func PosixToISO8601(posix float64) string { - t := time.Unix(int64(posix), 0).UTC() - return t.Format(time.RFC3339) -} diff --git a/core/api/util/util.go b/core/api/util/util.go index db6e3e427f..25eacf1d25 100644 --- a/core/api/util/util.go +++ b/core/api/util/util.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "time" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pb/service" @@ -17,6 +18,11 @@ var ( ErrorTypeNotFound = errors.New("type not found") ) +func PosixToISO8601(posix float64) string { + t := time.Unix(int64(posix), 0).UTC() + return t.Format(time.RFC3339) +} + // GetIconFromEmojiOrImage returns the icon to use for the object, which can be either an emoji or an image url func GetIconFromEmojiOrImage(accountInfo *model.AccountInfo, iconEmoji string, iconImage string) string { if iconEmoji != "" { @@ -65,7 +71,7 @@ func ResolveRelationKeyToRelationName(mw service.ClientCommandsServer, spaceId s Value: pbtypes.String(relationKey), }, }, - Keys: []string{bundle.RelationKeyId.String()}, + Keys: []string{bundle.RelationKeyId.String(), bundle.RelationKeyName.String()}, }) if resp.Error.Code != pb.RpcObjectSearchResponseError_NULL { From ce783a72e31b470cc306ba3d5d43cf422855af62 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sun, 16 Feb 2025 12:00:47 +0100 Subject: [PATCH 20/31] GO-4459: Fix security definition to ApiKey auth --- core/api/docs/docs.go | 26 ++++++++++++++++++++------ core/api/docs/swagger.json | 26 ++++++++++++++++++++------ core/api/docs/swagger.yaml | 18 +++++++++++++----- core/api/service.go | 4 +++- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 0c3db26bad..019faf5d95 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -1356,6 +1356,14 @@ const docTemplate = `{ "type": "string", "example": "64394517de52ad5acb89c66c" }, + "relation": { + "description": "The relation of the block, if applicable", + "allOf": [ + { + "$ref": "#/definitions/object.Relation" + } + ] + }, "text": { "description": "The text of the block, if applicable", "allOf": [ @@ -1560,6 +1568,14 @@ const docTemplate = `{ } } }, + "object.Relation": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, "object.Template": { "type": "object", "properties": { @@ -2140,13 +2156,11 @@ const docTemplate = `{ } }, "securityDefinitions": { - "BasicAuth": { - "type": "basic" + "ApiKeyAuth": { + "type": "apiKey", + "name": "Authorization", + "in": "header" } - }, - "externalDocs": { - "description": "OpenAPI", - "url": "https://swagger.io/resources/open-api/" } }` diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index 223b833839..f0af08881c 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -1350,6 +1350,14 @@ "type": "string", "example": "64394517de52ad5acb89c66c" }, + "relation": { + "description": "The relation of the block, if applicable", + "allOf": [ + { + "$ref": "#/definitions/object.Relation" + } + ] + }, "text": { "description": "The text of the block, if applicable", "allOf": [ @@ -1554,6 +1562,14 @@ } } }, + "object.Relation": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, "object.Template": { "type": "object", "properties": { @@ -2134,12 +2150,10 @@ } }, "securityDefinitions": { - "BasicAuth": { - "type": "basic" + "ApiKeyAuth": { + "type": "apiKey", + "name": "Authorization", + "in": "header" } - }, - "externalDocs": { - "description": "OpenAPI", - "url": "https://swagger.io/resources/open-api/" } } \ No newline at end of file diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 0dd2b302ac..c4dfe63d13 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -56,6 +56,10 @@ definitions: description: The id of the block example: 64394517de52ad5acb89c66c type: string + relation: + allOf: + - $ref: '#/definitions/object.Relation' + description: The relation of the block, if applicable text: allOf: - $ref: '#/definitions/object.Text' @@ -205,6 +209,11 @@ definitions: - $ref: '#/definitions/object.Object' description: The object type: object + object.Relation: + properties: + id: + type: string + type: object object.Template: properties: icon: @@ -615,9 +624,6 @@ definitions: type: string type: object type: object -externalDocs: - description: OpenAPI - url: https://swagger.io/resources/open-api/ host: localhost:31009 info: contact: @@ -1476,6 +1482,8 @@ paths: tags: - lists securityDefinitions: - BasicAuth: - type: basic + ApiKeyAuth: + in: header + name: Authorization + type: apiKey swagger: "2.0" diff --git a/core/api/service.go b/core/api/service.go index 6027337b64..d6cb17d475 100644 --- a/core/api/service.go +++ b/core/api/service.go @@ -60,7 +60,9 @@ func (s *apiService) Name() (name string) { // @license.url https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md // @host localhost:31009 // @BasePath /v1 -// @securityDefinitions.basic BasicAuth +// @securityDefinitions.apikey ApiKeyAuth +// @in header +// @name Authorization // @externalDocs.description OpenAPI // @externalDocs.url https://swagger.io/resources/open-api/ func (s *apiService) Init(a *app.App) (err error) { From 0a0ef5317dcd2dd0b706509cba51a5a0d60ea51c Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sun, 16 Feb 2025 12:59:37 +0100 Subject: [PATCH 21/31] GO-4459: Upgrade to OpenAPI specification v3.1 and swaggo/swag v2 --- core/api/docs/docs.go | 2173 +------------------------- core/api/docs/swagger.json | 2165 +------------------------- core/api/docs/swagger.yaml | 2204 +++++++++++++++------------ core/api/internal/export/handler.go | 1 + core/api/internal/list/handler.go | 25 +- core/api/internal/list/service.go | 8 +- core/api/internal/object/handler.go | 15 +- core/api/internal/search/handler.go | 2 + core/api/internal/space/handler.go | 9 +- core/api/server/router.go | 2 +- core/api/service.go | 30 +- go.mod | 12 +- go.sum | 16 + 13 files changed, 1276 insertions(+), 5386 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 019faf5d95..2faeb5526a 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -1,2175 +1,24 @@ -// Package docs Code generated by swaggo/swag. DO NOT EDIT +// Code generated by swaggo/swag. DO NOT EDIT. + package docs -import "github.com/swaggo/swag" +import "github.com/swaggo/swag/v2" const docTemplate = `{ "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "termsOfService": "https://anytype.io/terms_of_use", - "contact": { - "name": "Anytype Support", - "url": "https://anytype.io/contact", - "email": "support@anytype.io" - }, - "license": { - "name": "Any Source Available License 1.0", - "url": "https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md" - }, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": { - "/auth/display_code": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Start new challenge", - "parameters": [ - { - "type": "string", - "description": "App name requesting the challenge", - "name": "app_name", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Challenge ID", - "schema": { - "$ref": "#/definitions/auth.DisplayCodeResponse" - } - }, - "400": { - "description": "Invalid input", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/auth/token": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Retrieve token", - "parameters": [ - { - "type": "string", - "description": "Challenge ID", - "name": "challenge_id", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "4-digit code retrieved from Anytype Desktop app", - "name": "code", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Authentication token", - "schema": { - "$ref": "#/definitions/auth.TokenResponse" - } - }, - "400": { - "description": "Invalid input", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/search": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "search" - ], - "summary": "Search objects across all spaces", - "parameters": [ - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - }, - { - "description": "Search parameters", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/search.SearchRequest" - } - } - ], - "responses": { - "200": { - "description": "List of objects", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "List spaces", - "parameters": [ - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of spaces", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-space_Space" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "Create space", - "parameters": [ - { - "description": "Space to create", - "name": "name", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/space.CreateSpaceRequest" - } - } - ], - "responses": { - "200": { - "description": "Space created successfully", - "schema": { - "$ref": "#/definitions/space.SpaceResponse" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "423": { - "description": "Rate limit exceeded", - "schema": { - "$ref": "#/definitions/util.RateLimitError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "Get space", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Space", - "schema": { - "$ref": "#/definitions/space.SpaceResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Space not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/members": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "List members", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of members", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-space_Member" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/members/{member_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "Get member", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Member ID", - "name": "member_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Member", - "schema": { - "$ref": "#/definitions/space.MemberResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Member not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/objects": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "objects" - ], - "summary": "List objects", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of objects", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "objects" - ], - "summary": "Create object", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "description": "Object to create", - "name": "object", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/object.CreateObjectRequest" - } - } - ], - "responses": { - "200": { - "description": "The created object", - "schema": { - "$ref": "#/definitions/object.ObjectResponse" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "423": { - "description": "Rate limit exceeded", - "schema": { - "$ref": "#/definitions/util.RateLimitError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/objects/{object_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "objects" - ], - "summary": "Get object", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Object ID", - "name": "object_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "The requested object", - "schema": { - "$ref": "#/definitions/object.ObjectResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Resource not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "objects" - ], - "summary": "Delete object", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Object ID", - "name": "object_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "The deleted object", - "schema": { - "$ref": "#/definitions/object.ObjectResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/util.ForbiddenError" - } - }, - "404": { - "description": "Resource not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "423": { - "description": "Rate limit exceeded", - "schema": { - "$ref": "#/definitions/util.RateLimitError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/objects/{object_id}/export/{format}": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "export" - ], - "summary": "Export object", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Object ID", - "name": "object_id", - "in": "path", - "required": true - }, - { - "enum": [ - "markdown", - "protobuf" - ], - "type": "string", - "description": "Export format", - "name": "format", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Object exported successfully", - "schema": { - "$ref": "#/definitions/export.ObjectExportResponse" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/search": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "search" - ], - "summary": "Search objects within a space", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - }, - { - "description": "Search parameters", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/search.SearchRequest" - } - } - ], - "responses": { - "200": { - "description": "List of objects", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/types": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "types" - ], - "summary": "List types", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of types", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Type" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/types/{type_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "types" - ], - "summary": "Get type", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Type ID", - "name": "type_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "The requested type", - "schema": { - "$ref": "#/definitions/object.TypeResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Resource not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/types/{type_id}/templates": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "types" - ], - "summary": "List templates", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Type ID", - "name": "type_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of templates", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Template" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/types/{type_id}/templates/{template_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "types" - ], - "summary": "Get template", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Type ID", - "name": "type_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Template ID", - "name": "template_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "The requested template", - "schema": { - "$ref": "#/definitions/object.TemplateResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Resource not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/v1/spaces/{space_id}/lists/{list_id}/objects": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "lists" - ], - "summary": "Get objects in list", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "List ID", - "name": "list_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of objects", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "lists" - ], - "summary": "Add objects to list", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "List ID", - "name": "list_id", - "in": "path", - "required": true - }, - { - "description": "List of object IDs", - "name": "objects", - "in": "body", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - ], - "responses": { - "200": { - "description": "Objects added successfully", - "schema": { - "type": "string" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "lists" - ], - "summary": "Remove objects from list", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "List ID", - "name": "list_id", - "in": "path", - "required": true - }, - { - "description": "List of object IDs", - "name": "objects", - "in": "body", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - ], - "responses": { - "200": { - "description": "Objects removed successfully", - "schema": { - "type": "string" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - } - }, - "definitions": { - "auth.DisplayCodeResponse": { - "type": "object", - "properties": { - "challenge_id": { - "description": "The challenge id associated with the displayed code and needed to solve the challenge for token", - "type": "string", - "example": "67647f5ecda913e9a2e11b26" - } - } - }, - "auth.TokenResponse": { - "type": "object", - "properties": { - "app_key": { - "description": "The permanent app key", - "type": "string", - "example": "zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=" - }, - "session_token": { - "description": "The ephemeral session token", - "type": "string", - "example": "eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII" - } - } - }, - "export.ObjectExportResponse": { - "type": "object", - "properties": { - "path": { - "description": "The path the object was exported to", - "type": "string", - "example": "/path/to/export" - } - } - }, - "object.Block": { - "type": "object", - "properties": { - "align": { - "description": "The alignment of the block", - "type": "string", - "enum": [ - "AlignLeft", - "AlignCenter", - "AlignRight", - "AlignJustify" - ], - "example": "AlignLeft" - }, - "background_color": { - "description": "The background color of the block", - "type": "string", - "example": "red" - }, - "children_ids": { - "description": "The ids of the block's children", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "['6797ce8ecda913cde14b02dc']" - ] - }, - "file": { - "description": "The file of the block, if applicable", - "allOf": [ - { - "$ref": "#/definitions/object.File" - } - ] - }, - "id": { - "description": "The id of the block", - "type": "string", - "example": "64394517de52ad5acb89c66c" - }, - "relation": { - "description": "The relation of the block, if applicable", - "allOf": [ - { - "$ref": "#/definitions/object.Relation" - } - ] - }, - "text": { - "description": "The text of the block, if applicable", - "allOf": [ - { - "$ref": "#/definitions/object.Text" - } - ] - }, - "vertical_align": { - "description": "The vertical alignment of the block", - "type": "string", - "enum": [ - "VerticalAlignTop", - "VerticalAlignMiddle", - "VerticalAlignBottom" - ], - "example": "VerticalAlignTop" - } - } - }, - "object.CreateObjectRequest": { - "type": "object", - "properties": { - "body": { - "description": "The body of the object", - "type": "string", - "example": "This is the body of the object. Markdown syntax is supported here." - }, - "description": { - "description": "The description of the object", - "type": "string", - "example": "This is a description of the object." - }, - "icon": { - "description": "The icon of the object", - "type": "string", - "example": "📄" - }, - "name": { - "description": "The name of the object", - "type": "string", - "example": "My object" - }, - "object_type_unique_key": { - "description": "The unique key of the object type", - "type": "string", - "example": "ot-page" - }, - "source": { - "description": "The source url, only applicable for bookmarks", - "type": "string", - "example": "https://bookmark-source.com" - }, - "template_id": { - "description": "The id of the template to use", - "type": "string", - "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge" - } - } - }, - "object.Detail": { - "type": "object", - "properties": { - "details": { - "description": "The details", - "type": "object", - "additionalProperties": true - }, - "id": { - "description": "The id of the detail", - "type": "string", - "enum": [ - "last_modified_date", - "last_modified_by", - "created_date", - "created_by", - "last_opened_date", - "tags" - ], - "example": "last_modified_date" - } - } - }, - "object.File": { - "type": "object", - "properties": { - "added_at": { - "description": "The added at of the file", - "type": "integer" - }, - "hash": { - "description": "The hash of the file", - "type": "string" - }, - "mime": { - "description": "The mime of the file", - "type": "string" - }, - "name": { - "description": "The name of the file", - "type": "string" - }, - "size": { - "description": "The size of the file", - "type": "integer" - }, - "state": { - "description": "The state of the file", - "type": "string" - }, - "style": { - "description": "The style of the file", - "type": "string" - }, - "target_object_id": { - "description": "The target object id of the file", - "type": "string" - }, - "type": { - "description": "The type of the file", - "type": "string" - } - } - }, - "object.Object": { - "type": "object", - "properties": { - "blocks": { - "description": "The blocks of the object", - "type": "array", - "items": { - "$ref": "#/definitions/object.Block" - } - }, - "details": { - "description": "The details of the object", - "type": "array", - "items": { - "$ref": "#/definitions/object.Detail" - } - }, - "icon": { - "description": "The icon of the object", - "type": "string", - "example": "📄" - }, - "id": { - "description": "The id of the object", - "type": "string", - "example": "bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ" - }, - "layout": { - "description": "The layout of the object", - "type": "string", - "example": "basic" - }, - "name": { - "description": "The name of the object", - "type": "string", - "example": "My object" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "object" - }, - "root_id": { - "description": "The id of the object's root", - "type": "string", - "example": "bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u" - }, - "snippet": { - "description": "The snippet of the object, especially important for notes as they don't have a name", - "type": "string", - "example": "The beginning of the object body..." - }, - "space_id": { - "description": "The id of the space the object is in", - "type": "string", - "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1" - }, - "type": { - "description": "The type of the object", - "allOf": [ - { - "$ref": "#/definitions/object.Type" - } - ] - } - } - }, - "object.ObjectResponse": { - "type": "object", - "properties": { - "object": { - "description": "The object", - "allOf": [ - { - "$ref": "#/definitions/object.Object" - } - ] - } - } - }, - "object.Relation": { - "type": "object", - "properties": { - "id": { - "type": "string" - } - } - }, - "object.Template": { - "type": "object", - "properties": { - "icon": { - "description": "The icon of the template", - "type": "string", - "example": "📄" - }, - "id": { - "description": "The id of the template", - "type": "string", - "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge" - }, - "name": { - "description": "The name of the template", - "type": "string", - "example": "My template" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "template" - } - } - }, - "object.TemplateResponse": { - "type": "object", - "properties": { - "template": { - "description": "The template", - "allOf": [ - { - "$ref": "#/definitions/object.Template" - } - ] - } - } - }, - "object.Text": { - "type": "object", - "properties": { - "checked": { - "description": "Whether the text is checked", - "type": "boolean", - "example": true - }, - "color": { - "description": "The color of the text", - "type": "string", - "example": "red" - }, - "icon": { - "description": "The icon of the text", - "type": "string", - "example": "📄" - }, - "style": { - "description": "The style of the text", - "type": "string", - "enum": [ - "Paragraph", - "Header1", - "Header2", - "Header3", - "Header4", - "Quote", - "Code", - "Title", - "Checkbox", - "Marked", - "Numbered", - "Toggle", - "Description", - "Callout" - ], - "example": "Paragraph" - }, - "text": { - "description": "The text", - "type": "string", - "example": "Some text..." - } - } - }, - "object.Type": { - "type": "object", - "properties": { - "icon": { - "description": "The icon of the type", - "type": "string", - "example": "📄" - }, - "id": { - "description": "The id of the type", - "type": "string", - "example": "bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu" - }, - "name": { - "description": "The name of the type", - "type": "string", - "example": "Page" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "type" - }, - "recommended_layout": { - "description": "The recommended layout of the type", - "type": "string", - "example": "todo" - }, - "unique_key": { - "description": "The unique key of the type", - "type": "string", - "example": "ot-page" - } - } - }, - "object.TypeResponse": { - "type": "object", - "properties": { - "type": { - "description": "The type", - "allOf": [ - { - "$ref": "#/definitions/object.Type" - } - ] - } - } - }, - "pagination.PaginatedResponse-object_Object": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/object.Object" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginatedResponse-object_Template": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/object.Template" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginatedResponse-object_Type": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/object.Type" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginatedResponse-space_Member": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/space.Member" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginatedResponse-space_Space": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/space.Space" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginationMeta": { - "type": "object", - "properties": { - "has_more": { - "description": "Indicates if there are more items available beyond the current result set", - "type": "boolean", - "example": true - }, - "limit": { - "description": "The maximum number of items returned in the result set", - "type": "integer", - "example": 100 - }, - "offset": { - "description": "The number of items skipped before starting to collect the result set", - "type": "integer", - "example": 0 - }, - "total": { - "description": "The total number of items available for the endpoint", - "type": "integer", - "example": 1024 - } - } - }, - "search.SearchRequest": { - "type": "object", - "properties": { - "query": { - "description": "The search term to look for in object names and snippets", - "type": "string", - "example": "test" - }, - "sort": { - "description": "The sorting criteria and direction for the search results", - "allOf": [ - { - "$ref": "#/definitions/search.SortOptions" - } - ] - }, - "types": { - "description": "The types of objects to search for, specified by unique key or ID", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "ot-note", - "ot-page", - "ot-678043f0cda9133be777049f", - "bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q" - ] - } - } - }, - "search.SortOptions": { - "type": "object", - "properties": { - "direction": { - "description": "The direction to sort the search results", - "type": "string", - "default": "desc", - "enum": [ - "asc", - "desc" - ] - }, - "timestamp": { - "description": "The timestamp to sort the search results by", - "type": "string", - "default": "last_modified_date", - "enum": [ - "created_date", - "last_modified_date", - "last_opened_date" - ] - } - } - }, - "space.CreateSpaceRequest": { - "type": "object", - "properties": { - "name": { - "description": "The name of the space", - "type": "string", - "example": "New Space" - } - } - }, - "space.Member": { - "type": "object", - "properties": { - "global_name": { - "description": "The global name of the member in the network", - "type": "string", - "example": "john.any" - }, - "icon": { - "description": "The icon of the member", - "type": "string", - "example": "http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100" - }, - "id": { - "description": "The profile object id of the member", - "type": "string", - "example": "_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ" - }, - "identity": { - "description": "The identity of the member in the network", - "type": "string", - "example": "AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ" - }, - "name": { - "description": "The name of the member", - "type": "string", - "example": "John Doe" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "member" - }, - "role": { - "description": "The role of the member", - "type": "string", - "enum": [ - "Reader", - "Writer", - "Owner", - "NoPermission" - ], - "example": "Owner" - } - } - }, - "space.MemberResponse": { - "type": "object", - "properties": { - "member": { - "description": "The member", - "allOf": [ - { - "$ref": "#/definitions/space.Member" - } - ] - } - } - }, - "space.Space": { - "type": "object", - "properties": { - "account_space_id": { - "description": "The id of the account space", - "type": "string", - "example": "bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1" - }, - "analytics_id": { - "description": "The analytics id of the account", - "type": "string", - "example": "624aecdd-4797-4611-9d61-a2ae5f53cf1c" - }, - "archive_object_id": { - "description": "The id of the archive object", - "type": "string", - "example": "bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri" - }, - "device_id": { - "description": "The id of the device", - "type": "string", - "example": "12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF" - }, - "gateway_url": { - "description": "The gateway url to serve files and media", - "type": "string", - "example": "http://127.0.0.1:31006" - }, - "home_object_id": { - "description": "The id of the home object", - "type": "string", - "example": "bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya" - }, - "icon": { - "description": "The icon of the space", - "type": "string", - "example": "http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay" - }, - "id": { - "description": "The id of the space", - "type": "string", - "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1" - }, - "local_storage_path": { - "description": "The local storage path of the account", - "type": "string", - "example": "/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha" - }, - "marketplace_workspace_id": { - "description": "The id of the marketplace workspace", - "type": "string", - "example": "_anytype_marketplace" - }, - "name": { - "description": "The name of the space", - "type": "string", - "example": "My Space" - }, - "network_id": { - "description": "The network id of the space", - "type": "string", - "example": "N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "space" - }, - "profile_object_id": { - "description": "The id of the profile object", - "type": "string", - "example": "bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4" - }, - "space_view_id": { - "description": "The id of the space view", - "type": "string", - "example": "bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy" - }, - "tech_space_id": { - "description": "The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself", - "type": "string", - "example": "bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1" - }, - "timezone": { - "description": "The timezone of the account", - "type": "string", - "example": "" - }, - "widgets_id": { - "description": "The id of the widgets", - "type": "string", - "example": "bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva" - }, - "workspace_object_id": { - "description": "The id of the workspace object", - "type": "string", - "example": "bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y" - } - } - }, - "space.SpaceResponse": { - "type": "object", - "properties": { - "space": { - "description": "The space", - "allOf": [ - { - "$ref": "#/definitions/space.Space" - } - ] - } - } - }, - "util.ForbiddenError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Forbidden" - } - } - } - } - }, - "util.NotFoundError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Resource not found" - } - } - } - } - }, - "util.RateLimitError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Rate limit exceeded" - } - } - } - } - }, - "util.ServerError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - }, - "util.UnauthorizedError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Unauthorized" - } - } - } - } - }, - "util.ValidationError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Bad request" - } - } - } - } - } - }, - "securityDefinitions": { - "ApiKeyAuth": { - "type": "apiKey", - "name": "Authorization", - "in": "header" - } - } + "components": {"schemas":{"auth.DisplayCodeResponse":{"properties":{"challenge_id":{"description":"The challenge id associated with the displayed code and needed to solve the challenge for token","example":"67647f5ecda913e9a2e11b26","type":"string"}},"type":"object"},"auth.TokenResponse":{"properties":{"app_key":{"description":"The permanent app key","example":"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=","type":"string"},"session_token":{"description":"The ephemeral session token","example":"eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII","type":"string"}},"type":"object"},"export.ObjectExportResponse":{"properties":{"path":{"description":"The path the object was exported to","example":"/path/to/export","type":"string"}},"type":"object"},"object.Block":{"properties":{"align":{"description":"The alignment of the block","enum":["AlignLeft","AlignCenter","AlignRight","AlignJustify"],"example":"AlignLeft","type":"string"},"background_color":{"description":"The background color of the block","example":"red","type":"string"},"children_ids":{"description":"The ids of the block's children","example":["['6797ce8ecda913cde14b02dc']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"file":{"$ref":"#/components/schemas/object.File"},"id":{"description":"The id of the block","example":"64394517de52ad5acb89c66c","type":"string"},"relation":{"$ref":"#/components/schemas/object.Relation"},"text":{"$ref":"#/components/schemas/object.Text"},"vertical_align":{"description":"The vertical alignment of the block","enum":["VerticalAlignTop","VerticalAlignMiddle","VerticalAlignBottom"],"example":"VerticalAlignTop","type":"string"}},"type":"object"},"object.CreateObjectRequest":{"properties":{"body":{"description":"The body of the object","example":"This is the body of the object. Markdown syntax is supported here.","type":"string"},"description":{"description":"The description of the object","example":"This is a description of the object.","type":"string"},"icon":{"description":"The icon of the object","example":"📄","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object_type_unique_key":{"description":"The unique key of the object type","example":"ot-page","type":"string"},"source":{"description":"The source url, only applicable for bookmarks","example":"https://bookmark-source.com","type":"string"},"template_id":{"description":"The id of the template to use","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"}},"type":"object"},"object.Detail":{"properties":{"details":{"additionalProperties":{},"description":"The details","type":"object"},"id":{"description":"The id of the detail","enum":["last_modified_date","last_modified_by","created_date","created_by","last_opened_date","tags"],"example":"last_modified_date","type":"string"}},"type":"object"},"object.File":{"description":"The file of the block, if applicable","properties":{"added_at":{"description":"The added at of the file","type":"integer"},"hash":{"description":"The hash of the file","type":"string"},"mime":{"description":"The mime of the file","type":"string"},"name":{"description":"The name of the file","type":"string"},"size":{"description":"The size of the file","type":"integer"},"state":{"description":"The state of the file","type":"string"},"style":{"description":"The style of the file","type":"string"},"target_object_id":{"description":"The target object id of the file","type":"string"},"type":{"description":"The type of the file","type":"string"}},"type":"object"},"object.Object":{"description":"The object","properties":{"blocks":{"description":"The blocks of the object","items":{"$ref":"#/components/schemas/object.Block"},"type":"array","uniqueItems":false},"details":{"description":"The details of the object","items":{"$ref":"#/components/schemas/object.Detail"},"type":"array","uniqueItems":false},"icon":{"description":"The icon of the object","example":"📄","type":"string"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"root_id":{"description":"The id of the object's root","example":"bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u","type":"string"},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/object.Type"}},"type":"object"},"object.ObjectResponse":{"properties":{"object":{"$ref":"#/components/schemas/object.Object"}},"type":"object"},"object.Relation":{"description":"The relation of the block, if applicable","properties":{"id":{"type":"string"}},"type":"object"},"object.Template":{"description":"The template","properties":{"icon":{"description":"The icon of the template","example":"📄","type":"string"},"id":{"description":"The id of the template","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"},"name":{"description":"The name of the template","example":"My template","type":"string"},"object":{"description":"The data model of the object","example":"template","type":"string"}},"type":"object"},"object.TemplateResponse":{"properties":{"template":{"$ref":"#/components/schemas/object.Template"}},"type":"object"},"object.Text":{"description":"The text of the block, if applicable","properties":{"checked":{"description":"Whether the text is checked","example":true,"type":"boolean"},"color":{"description":"The color of the text","example":"red","type":"string"},"icon":{"description":"The icon of the text","example":"📄","type":"string"},"style":{"description":"The style of the text","enum":["Paragraph","Header1","Header2","Header3","Header4","Quote","Code","Title","Checkbox","Marked","Numbered","Toggle","Description","Callout"],"example":"Paragraph","type":"string"},"text":{"description":"The text","example":"Some text...","type":"string"}},"type":"object"},"object.Type":{"description":"The type of the object","properties":{"icon":{"description":"The icon of the type","example":"📄","type":"string"},"id":{"description":"The id of the type","example":"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu","type":"string"},"name":{"description":"The name of the type","example":"Page","type":"string"},"object":{"description":"The data model of the object","example":"type","type":"string"},"recommended_layout":{"description":"The recommended layout of the type","example":"todo","type":"string"},"unique_key":{"description":"The unique key of the type","example":"ot-page","type":"string"}},"type":"object"},"object.TypeResponse":{"properties":{"type":{"$ref":"#/components/schemas/object.Type"}},"type":"object"},"pagination.PaginatedResponse-object_Object":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Object"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-object_Template":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Template"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-object_Type":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Type"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-space_Member":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/space.Member"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-space_Space":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/space.Space"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginationMeta":{"description":"The pagination metadata for the response","properties":{"has_more":{"description":"Indicates if there are more items available beyond the current result set","example":true,"type":"boolean"},"limit":{"description":"The maximum number of items returned in the result set","example":100,"type":"integer"},"offset":{"description":"The number of items skipped before starting to collect the result set","example":0,"type":"integer"},"total":{"description":"The total number of items available for the endpoint","example":1024,"type":"integer"}},"type":"object"},"search.SearchRequest":{"properties":{"query":{"description":"The search term to look for in object names and snippets","example":"test","type":"string"},"sort":{"$ref":"#/components/schemas/search.SortOptions"},"types":{"description":"The types of objects to search for, specified by unique key or ID","example":["ot-note","ot-page","ot-678043f0cda9133be777049f","bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"search.SortOptions":{"description":"The sorting criteria and direction for the search results","properties":{"direction":{"default":"desc","description":"The direction to sort the search results","enum":["asc","desc"],"type":"string"},"timestamp":{"default":"last_modified_date","description":"The timestamp to sort the search results by","enum":["created_date","last_modified_date","last_opened_date"],"type":"string"}},"type":"object"},"space.CreateSpaceRequest":{"properties":{"name":{"description":"The name of the space","example":"New Space","type":"string"}},"type":"object"},"space.Member":{"description":"The member","properties":{"global_name":{"description":"The global name of the member in the network","example":"john.any","type":"string"},"icon":{"description":"The icon of the member","example":"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100","type":"string"},"id":{"description":"The profile object id of the member","example":"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ","type":"string"},"identity":{"description":"The identity of the member in the network","example":"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ","type":"string"},"name":{"description":"The name of the member","example":"John Doe","type":"string"},"object":{"description":"The data model of the object","example":"member","type":"string"},"role":{"description":"The role of the member","enum":["Reader","Writer","Owner","NoPermission"],"example":"Owner","type":"string"}},"type":"object"},"space.MemberResponse":{"properties":{"member":{"$ref":"#/components/schemas/space.Member"}},"type":"object"},"space.Space":{"description":"The space","properties":{"account_space_id":{"description":"The id of the account space","example":"bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1","type":"string"},"analytics_id":{"description":"The analytics id of the account","example":"624aecdd-4797-4611-9d61-a2ae5f53cf1c","type":"string"},"archive_object_id":{"description":"The id of the archive object","example":"bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri","type":"string"},"device_id":{"description":"The id of the device","example":"12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF","type":"string"},"gateway_url":{"description":"The gateway url to serve files and media","example":"http://127.0.0.1:31006","type":"string"},"home_object_id":{"description":"The id of the home object","example":"bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya","type":"string"},"icon":{"description":"The icon of the space","example":"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay","type":"string"},"id":{"description":"The id of the space","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"local_storage_path":{"description":"The local storage path of the account","example":"/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha","type":"string"},"marketplace_workspace_id":{"description":"The id of the marketplace workspace","example":"_anytype_marketplace","type":"string"},"name":{"description":"The name of the space","example":"My Space","type":"string"},"network_id":{"description":"The network id of the space","example":"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU","type":"string"},"object":{"description":"The data model of the object","example":"space","type":"string"},"profile_object_id":{"description":"The id of the profile object","example":"bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4","type":"string"},"space_view_id":{"description":"The id of the space view","example":"bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy","type":"string"},"tech_space_id":{"description":"The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself","example":"bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1","type":"string"},"timezone":{"description":"The timezone of the account","example":"","type":"string"},"widgets_id":{"description":"The id of the widgets","example":"bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva","type":"string"},"workspace_object_id":{"description":"The id of the workspace object","example":"bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y","type":"string"}},"type":"object"},"space.SpaceResponse":{"properties":{"space":{"$ref":"#/components/schemas/space.Space"}},"type":"object"},"util.ForbiddenError":{"properties":{"error":{"properties":{"message":{"example":"Forbidden","type":"string"}},"type":"object"}},"type":"object"},"util.NotFoundError":{"properties":{"error":{"properties":{"message":{"example":"Resource not found","type":"string"}},"type":"object"}},"type":"object"},"util.RateLimitError":{"properties":{"error":{"properties":{"message":{"example":"Rate limit exceeded","type":"string"}},"type":"object"}},"type":"object"},"util.ServerError":{"properties":{"error":{"properties":{"message":{"example":"Internal server error","type":"string"}},"type":"object"}},"type":"object"},"util.UnauthorizedError":{"properties":{"error":{"properties":{"message":{"example":"Unauthorized","type":"string"}},"type":"object"}},"type":"object"},"util.ValidationError":{"properties":{"error":{"properties":{"message":{"example":"Bad request","type":"string"}},"type":"object"}},"type":"object"}},"securitySchemes":{"bearerauth":{"bearerFormat":"JWT","scheme":"bearer","type":"http"}}}, + "info": {"contact":{"email":"support@anytype.io","name":"Anytype Support","url":"https://anytype.io/contact"},"description":"{{escape .Description}}","license":{"name":"Any Source Available License 1.0","url":"https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md"},"termsOfService":"https://anytype.io/terms_of_use","title":"{{.Title}}","version":"{{.Version}}"}, + "externalDocs": {"description":"OpenAPI","url":"https://swagger.io/resources/open-api/"}, + "paths": {"/auth/display_code":{"post":{"parameters":[{"description":"App name requesting the challenge","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.DisplayCodeResponse"}}},"description":"Challenge ID"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["auth"]}},"/auth/token":{"post":{"parameters":[{"description":"Challenge ID","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.TokenResponse"}}},"description":"Authentication token"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Retrieve token","tags":["auth"]}},"/search":{"post":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["search"]}},"/spaces":{"get":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Space"}}},"description":"List of spaces"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["spaces"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.CreateSpaceRequest"}}},"description":"Space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space created successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["spaces"]}},"/spaces/{space_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["spaces"]}},"/spaces/{space_id}/members":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Member"}}},"description":"List of members"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["spaces"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.MemberResponse"}}},"description":"Member"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["spaces"]}},"/spaces/{space_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["objects"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.CreateObjectRequest"}}},"description":"Object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["objects"]},"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The requested object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}/export/{format}":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"Export format","in":"path","name":"format","required":true,"schema":{"enum":["markdown","protobuf"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/export.ObjectExportResponse"}}},"description":"Object exported successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Export object","tags":["export"]}},"/spaces/{space_id}/search":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["search"]}},"/spaces/{space_id}/types":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Type"}}},"description":"List of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["types"]}},"/spaces/{space_id}/types/{type_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Template"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"Template ID","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["types"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["lists"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"List of object IDs","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["lists"]}}}, + "openapi": "3.1.0", + "servers": [ + {"url":"localhost:31009/v1"} + ] }` // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ Version: "1.0", - Host: "localhost:31009", - BasePath: "/v1", - Schemes: []string{}, Title: "Anytype API", Description: "This API allows interaction with Anytype resources such as spaces, objects and types.", InfoInstanceName: "swagger", diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index f0af08881c..c79693d6bf 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -1,2159 +1,10 @@ { - "swagger": "2.0", - "info": { - "description": "This API allows interaction with Anytype resources such as spaces, objects and types.", - "title": "Anytype API", - "termsOfService": "https://anytype.io/terms_of_use", - "contact": { - "name": "Anytype Support", - "url": "https://anytype.io/contact", - "email": "support@anytype.io" - }, - "license": { - "name": "Any Source Available License 1.0", - "url": "https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md" - }, - "version": "1.0" - }, - "host": "localhost:31009", - "basePath": "/v1", - "paths": { - "/auth/display_code": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Start new challenge", - "parameters": [ - { - "type": "string", - "description": "App name requesting the challenge", - "name": "app_name", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Challenge ID", - "schema": { - "$ref": "#/definitions/auth.DisplayCodeResponse" - } - }, - "400": { - "description": "Invalid input", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/auth/token": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "auth" - ], - "summary": "Retrieve token", - "parameters": [ - { - "type": "string", - "description": "Challenge ID", - "name": "challenge_id", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "4-digit code retrieved from Anytype Desktop app", - "name": "code", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Authentication token", - "schema": { - "$ref": "#/definitions/auth.TokenResponse" - } - }, - "400": { - "description": "Invalid input", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/search": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "search" - ], - "summary": "Search objects across all spaces", - "parameters": [ - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - }, - { - "description": "Search parameters", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/search.SearchRequest" - } - } - ], - "responses": { - "200": { - "description": "List of objects", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "List spaces", - "parameters": [ - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of spaces", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-space_Space" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "Create space", - "parameters": [ - { - "description": "Space to create", - "name": "name", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/space.CreateSpaceRequest" - } - } - ], - "responses": { - "200": { - "description": "Space created successfully", - "schema": { - "$ref": "#/definitions/space.SpaceResponse" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "423": { - "description": "Rate limit exceeded", - "schema": { - "$ref": "#/definitions/util.RateLimitError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "Get space", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Space", - "schema": { - "$ref": "#/definitions/space.SpaceResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Space not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/members": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "List members", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of members", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-space_Member" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/members/{member_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "spaces" - ], - "summary": "Get member", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Member ID", - "name": "member_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Member", - "schema": { - "$ref": "#/definitions/space.MemberResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Member not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/objects": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "objects" - ], - "summary": "List objects", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of objects", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "objects" - ], - "summary": "Create object", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "description": "Object to create", - "name": "object", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/object.CreateObjectRequest" - } - } - ], - "responses": { - "200": { - "description": "The created object", - "schema": { - "$ref": "#/definitions/object.ObjectResponse" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "423": { - "description": "Rate limit exceeded", - "schema": { - "$ref": "#/definitions/util.RateLimitError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/objects/{object_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "objects" - ], - "summary": "Get object", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Object ID", - "name": "object_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "The requested object", - "schema": { - "$ref": "#/definitions/object.ObjectResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Resource not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "objects" - ], - "summary": "Delete object", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Object ID", - "name": "object_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "The deleted object", - "schema": { - "$ref": "#/definitions/object.ObjectResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/util.ForbiddenError" - } - }, - "404": { - "description": "Resource not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "423": { - "description": "Rate limit exceeded", - "schema": { - "$ref": "#/definitions/util.RateLimitError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/objects/{object_id}/export/{format}": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "export" - ], - "summary": "Export object", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Object ID", - "name": "object_id", - "in": "path", - "required": true - }, - { - "enum": [ - "markdown", - "protobuf" - ], - "type": "string", - "description": "Export format", - "name": "format", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Object exported successfully", - "schema": { - "$ref": "#/definitions/export.ObjectExportResponse" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/search": { - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "search" - ], - "summary": "Search objects within a space", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - }, - { - "description": "Search parameters", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/search.SearchRequest" - } - } - ], - "responses": { - "200": { - "description": "List of objects", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/types": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "types" - ], - "summary": "List types", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of types", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Type" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/types/{type_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "types" - ], - "summary": "Get type", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Type ID", - "name": "type_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "The requested type", - "schema": { - "$ref": "#/definitions/object.TypeResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Resource not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/types/{type_id}/templates": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "types" - ], - "summary": "List templates", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Type ID", - "name": "type_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "maximum": 1000, - "type": "integer", - "default": 100, - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of templates", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Template" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/spaces/{space_id}/types/{type_id}/templates/{template_id}": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "types" - ], - "summary": "Get template", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Type ID", - "name": "type_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Template ID", - "name": "template_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "The requested template", - "schema": { - "$ref": "#/definitions/object.TemplateResponse" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Resource not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - }, - "/v1/spaces/{space_id}/lists/{list_id}/objects": { - "get": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "lists" - ], - "summary": "Get objects in list", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "List ID", - "name": "list_id", - "in": "path", - "required": true - }, - { - "type": "integer", - "default": 0, - "description": "The number of items to skip before starting to collect the result set", - "name": "offset", - "in": "query" - }, - { - "type": "integer", - "description": "The number of items to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of objects", - "schema": { - "$ref": "#/definitions/pagination.PaginatedResponse-object_Object" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "post": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "lists" - ], - "summary": "Add objects to list", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "List ID", - "name": "list_id", - "in": "path", - "required": true - }, - { - "description": "List of object IDs", - "name": "objects", - "in": "body", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - ], - "responses": { - "200": { - "description": "Objects added successfully", - "schema": { - "type": "string" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - }, - "delete": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "lists" - ], - "summary": "Remove objects from list", - "parameters": [ - { - "type": "string", - "description": "Space ID", - "name": "space_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "List ID", - "name": "list_id", - "in": "path", - "required": true - }, - { - "description": "List of object IDs", - "name": "objects", - "in": "body", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - ], - "responses": { - "200": { - "description": "Objects removed successfully", - "schema": { - "type": "string" - } - }, - "400": { - "description": "Bad request", - "schema": { - "$ref": "#/definitions/util.ValidationError" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "$ref": "#/definitions/util.UnauthorizedError" - } - }, - "404": { - "description": "Not found", - "schema": { - "$ref": "#/definitions/util.NotFoundError" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/util.ServerError" - } - } - } - } - } - }, - "definitions": { - "auth.DisplayCodeResponse": { - "type": "object", - "properties": { - "challenge_id": { - "description": "The challenge id associated with the displayed code and needed to solve the challenge for token", - "type": "string", - "example": "67647f5ecda913e9a2e11b26" - } - } - }, - "auth.TokenResponse": { - "type": "object", - "properties": { - "app_key": { - "description": "The permanent app key", - "type": "string", - "example": "zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=" - }, - "session_token": { - "description": "The ephemeral session token", - "type": "string", - "example": "eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII" - } - } - }, - "export.ObjectExportResponse": { - "type": "object", - "properties": { - "path": { - "description": "The path the object was exported to", - "type": "string", - "example": "/path/to/export" - } - } - }, - "object.Block": { - "type": "object", - "properties": { - "align": { - "description": "The alignment of the block", - "type": "string", - "enum": [ - "AlignLeft", - "AlignCenter", - "AlignRight", - "AlignJustify" - ], - "example": "AlignLeft" - }, - "background_color": { - "description": "The background color of the block", - "type": "string", - "example": "red" - }, - "children_ids": { - "description": "The ids of the block's children", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "['6797ce8ecda913cde14b02dc']" - ] - }, - "file": { - "description": "The file of the block, if applicable", - "allOf": [ - { - "$ref": "#/definitions/object.File" - } - ] - }, - "id": { - "description": "The id of the block", - "type": "string", - "example": "64394517de52ad5acb89c66c" - }, - "relation": { - "description": "The relation of the block, if applicable", - "allOf": [ - { - "$ref": "#/definitions/object.Relation" - } - ] - }, - "text": { - "description": "The text of the block, if applicable", - "allOf": [ - { - "$ref": "#/definitions/object.Text" - } - ] - }, - "vertical_align": { - "description": "The vertical alignment of the block", - "type": "string", - "enum": [ - "VerticalAlignTop", - "VerticalAlignMiddle", - "VerticalAlignBottom" - ], - "example": "VerticalAlignTop" - } - } - }, - "object.CreateObjectRequest": { - "type": "object", - "properties": { - "body": { - "description": "The body of the object", - "type": "string", - "example": "This is the body of the object. Markdown syntax is supported here." - }, - "description": { - "description": "The description of the object", - "type": "string", - "example": "This is a description of the object." - }, - "icon": { - "description": "The icon of the object", - "type": "string", - "example": "📄" - }, - "name": { - "description": "The name of the object", - "type": "string", - "example": "My object" - }, - "object_type_unique_key": { - "description": "The unique key of the object type", - "type": "string", - "example": "ot-page" - }, - "source": { - "description": "The source url, only applicable for bookmarks", - "type": "string", - "example": "https://bookmark-source.com" - }, - "template_id": { - "description": "The id of the template to use", - "type": "string", - "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge" - } - } - }, - "object.Detail": { - "type": "object", - "properties": { - "details": { - "description": "The details", - "type": "object", - "additionalProperties": true - }, - "id": { - "description": "The id of the detail", - "type": "string", - "enum": [ - "last_modified_date", - "last_modified_by", - "created_date", - "created_by", - "last_opened_date", - "tags" - ], - "example": "last_modified_date" - } - } - }, - "object.File": { - "type": "object", - "properties": { - "added_at": { - "description": "The added at of the file", - "type": "integer" - }, - "hash": { - "description": "The hash of the file", - "type": "string" - }, - "mime": { - "description": "The mime of the file", - "type": "string" - }, - "name": { - "description": "The name of the file", - "type": "string" - }, - "size": { - "description": "The size of the file", - "type": "integer" - }, - "state": { - "description": "The state of the file", - "type": "string" - }, - "style": { - "description": "The style of the file", - "type": "string" - }, - "target_object_id": { - "description": "The target object id of the file", - "type": "string" - }, - "type": { - "description": "The type of the file", - "type": "string" - } - } - }, - "object.Object": { - "type": "object", - "properties": { - "blocks": { - "description": "The blocks of the object", - "type": "array", - "items": { - "$ref": "#/definitions/object.Block" - } - }, - "details": { - "description": "The details of the object", - "type": "array", - "items": { - "$ref": "#/definitions/object.Detail" - } - }, - "icon": { - "description": "The icon of the object", - "type": "string", - "example": "📄" - }, - "id": { - "description": "The id of the object", - "type": "string", - "example": "bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ" - }, - "layout": { - "description": "The layout of the object", - "type": "string", - "example": "basic" - }, - "name": { - "description": "The name of the object", - "type": "string", - "example": "My object" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "object" - }, - "root_id": { - "description": "The id of the object's root", - "type": "string", - "example": "bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u" - }, - "snippet": { - "description": "The snippet of the object, especially important for notes as they don't have a name", - "type": "string", - "example": "The beginning of the object body..." - }, - "space_id": { - "description": "The id of the space the object is in", - "type": "string", - "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1" - }, - "type": { - "description": "The type of the object", - "allOf": [ - { - "$ref": "#/definitions/object.Type" - } - ] - } - } - }, - "object.ObjectResponse": { - "type": "object", - "properties": { - "object": { - "description": "The object", - "allOf": [ - { - "$ref": "#/definitions/object.Object" - } - ] - } - } - }, - "object.Relation": { - "type": "object", - "properties": { - "id": { - "type": "string" - } - } - }, - "object.Template": { - "type": "object", - "properties": { - "icon": { - "description": "The icon of the template", - "type": "string", - "example": "📄" - }, - "id": { - "description": "The id of the template", - "type": "string", - "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge" - }, - "name": { - "description": "The name of the template", - "type": "string", - "example": "My template" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "template" - } - } - }, - "object.TemplateResponse": { - "type": "object", - "properties": { - "template": { - "description": "The template", - "allOf": [ - { - "$ref": "#/definitions/object.Template" - } - ] - } - } - }, - "object.Text": { - "type": "object", - "properties": { - "checked": { - "description": "Whether the text is checked", - "type": "boolean", - "example": true - }, - "color": { - "description": "The color of the text", - "type": "string", - "example": "red" - }, - "icon": { - "description": "The icon of the text", - "type": "string", - "example": "📄" - }, - "style": { - "description": "The style of the text", - "type": "string", - "enum": [ - "Paragraph", - "Header1", - "Header2", - "Header3", - "Header4", - "Quote", - "Code", - "Title", - "Checkbox", - "Marked", - "Numbered", - "Toggle", - "Description", - "Callout" - ], - "example": "Paragraph" - }, - "text": { - "description": "The text", - "type": "string", - "example": "Some text..." - } - } - }, - "object.Type": { - "type": "object", - "properties": { - "icon": { - "description": "The icon of the type", - "type": "string", - "example": "📄" - }, - "id": { - "description": "The id of the type", - "type": "string", - "example": "bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu" - }, - "name": { - "description": "The name of the type", - "type": "string", - "example": "Page" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "type" - }, - "recommended_layout": { - "description": "The recommended layout of the type", - "type": "string", - "example": "todo" - }, - "unique_key": { - "description": "The unique key of the type", - "type": "string", - "example": "ot-page" - } - } - }, - "object.TypeResponse": { - "type": "object", - "properties": { - "type": { - "description": "The type", - "allOf": [ - { - "$ref": "#/definitions/object.Type" - } - ] - } - } - }, - "pagination.PaginatedResponse-object_Object": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/object.Object" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginatedResponse-object_Template": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/object.Template" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginatedResponse-object_Type": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/object.Type" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginatedResponse-space_Member": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/space.Member" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginatedResponse-space_Space": { - "type": "object", - "properties": { - "data": { - "description": "The list of items in the current result set", - "type": "array", - "items": { - "$ref": "#/definitions/space.Space" - } - }, - "pagination": { - "description": "The pagination metadata for the response", - "allOf": [ - { - "$ref": "#/definitions/pagination.PaginationMeta" - } - ] - } - } - }, - "pagination.PaginationMeta": { - "type": "object", - "properties": { - "has_more": { - "description": "Indicates if there are more items available beyond the current result set", - "type": "boolean", - "example": true - }, - "limit": { - "description": "The maximum number of items returned in the result set", - "type": "integer", - "example": 100 - }, - "offset": { - "description": "The number of items skipped before starting to collect the result set", - "type": "integer", - "example": 0 - }, - "total": { - "description": "The total number of items available for the endpoint", - "type": "integer", - "example": 1024 - } - } - }, - "search.SearchRequest": { - "type": "object", - "properties": { - "query": { - "description": "The search term to look for in object names and snippets", - "type": "string", - "example": "test" - }, - "sort": { - "description": "The sorting criteria and direction for the search results", - "allOf": [ - { - "$ref": "#/definitions/search.SortOptions" - } - ] - }, - "types": { - "description": "The types of objects to search for, specified by unique key or ID", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "ot-note", - "ot-page", - "ot-678043f0cda9133be777049f", - "bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q" - ] - } - } - }, - "search.SortOptions": { - "type": "object", - "properties": { - "direction": { - "description": "The direction to sort the search results", - "type": "string", - "default": "desc", - "enum": [ - "asc", - "desc" - ] - }, - "timestamp": { - "description": "The timestamp to sort the search results by", - "type": "string", - "default": "last_modified_date", - "enum": [ - "created_date", - "last_modified_date", - "last_opened_date" - ] - } - } - }, - "space.CreateSpaceRequest": { - "type": "object", - "properties": { - "name": { - "description": "The name of the space", - "type": "string", - "example": "New Space" - } - } - }, - "space.Member": { - "type": "object", - "properties": { - "global_name": { - "description": "The global name of the member in the network", - "type": "string", - "example": "john.any" - }, - "icon": { - "description": "The icon of the member", - "type": "string", - "example": "http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100" - }, - "id": { - "description": "The profile object id of the member", - "type": "string", - "example": "_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ" - }, - "identity": { - "description": "The identity of the member in the network", - "type": "string", - "example": "AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ" - }, - "name": { - "description": "The name of the member", - "type": "string", - "example": "John Doe" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "member" - }, - "role": { - "description": "The role of the member", - "type": "string", - "enum": [ - "Reader", - "Writer", - "Owner", - "NoPermission" - ], - "example": "Owner" - } - } - }, - "space.MemberResponse": { - "type": "object", - "properties": { - "member": { - "description": "The member", - "allOf": [ - { - "$ref": "#/definitions/space.Member" - } - ] - } - } - }, - "space.Space": { - "type": "object", - "properties": { - "account_space_id": { - "description": "The id of the account space", - "type": "string", - "example": "bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1" - }, - "analytics_id": { - "description": "The analytics id of the account", - "type": "string", - "example": "624aecdd-4797-4611-9d61-a2ae5f53cf1c" - }, - "archive_object_id": { - "description": "The id of the archive object", - "type": "string", - "example": "bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri" - }, - "device_id": { - "description": "The id of the device", - "type": "string", - "example": "12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF" - }, - "gateway_url": { - "description": "The gateway url to serve files and media", - "type": "string", - "example": "http://127.0.0.1:31006" - }, - "home_object_id": { - "description": "The id of the home object", - "type": "string", - "example": "bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya" - }, - "icon": { - "description": "The icon of the space", - "type": "string", - "example": "http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay" - }, - "id": { - "description": "The id of the space", - "type": "string", - "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1" - }, - "local_storage_path": { - "description": "The local storage path of the account", - "type": "string", - "example": "/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha" - }, - "marketplace_workspace_id": { - "description": "The id of the marketplace workspace", - "type": "string", - "example": "_anytype_marketplace" - }, - "name": { - "description": "The name of the space", - "type": "string", - "example": "My Space" - }, - "network_id": { - "description": "The network id of the space", - "type": "string", - "example": "N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU" - }, - "object": { - "description": "The data model of the object", - "type": "string", - "example": "space" - }, - "profile_object_id": { - "description": "The id of the profile object", - "type": "string", - "example": "bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4" - }, - "space_view_id": { - "description": "The id of the space view", - "type": "string", - "example": "bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy" - }, - "tech_space_id": { - "description": "The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself", - "type": "string", - "example": "bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1" - }, - "timezone": { - "description": "The timezone of the account", - "type": "string", - "example": "" - }, - "widgets_id": { - "description": "The id of the widgets", - "type": "string", - "example": "bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva" - }, - "workspace_object_id": { - "description": "The id of the workspace object", - "type": "string", - "example": "bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y" - } - } - }, - "space.SpaceResponse": { - "type": "object", - "properties": { - "space": { - "description": "The space", - "allOf": [ - { - "$ref": "#/definitions/space.Space" - } - ] - } - } - }, - "util.ForbiddenError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Forbidden" - } - } - } - } - }, - "util.NotFoundError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Resource not found" - } - } - } - } - }, - "util.RateLimitError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Rate limit exceeded" - } - } - } - } - }, - "util.ServerError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - }, - "util.UnauthorizedError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Unauthorized" - } - } - } - } - }, - "util.ValidationError": { - "type": "object", - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Bad request" - } - } - } - } - } - }, - "securityDefinitions": { - "ApiKeyAuth": { - "type": "apiKey", - "name": "Authorization", - "in": "header" - } - } + "components": {"schemas":{"auth.DisplayCodeResponse":{"properties":{"challenge_id":{"description":"The challenge id associated with the displayed code and needed to solve the challenge for token","example":"67647f5ecda913e9a2e11b26","type":"string"}},"type":"object"},"auth.TokenResponse":{"properties":{"app_key":{"description":"The permanent app key","example":"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=","type":"string"},"session_token":{"description":"The ephemeral session token","example":"eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII","type":"string"}},"type":"object"},"export.ObjectExportResponse":{"properties":{"path":{"description":"The path the object was exported to","example":"/path/to/export","type":"string"}},"type":"object"},"object.Block":{"properties":{"align":{"description":"The alignment of the block","enum":["AlignLeft","AlignCenter","AlignRight","AlignJustify"],"example":"AlignLeft","type":"string"},"background_color":{"description":"The background color of the block","example":"red","type":"string"},"children_ids":{"description":"The ids of the block's children","example":["['6797ce8ecda913cde14b02dc']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"file":{"$ref":"#/components/schemas/object.File"},"id":{"description":"The id of the block","example":"64394517de52ad5acb89c66c","type":"string"},"relation":{"$ref":"#/components/schemas/object.Relation"},"text":{"$ref":"#/components/schemas/object.Text"},"vertical_align":{"description":"The vertical alignment of the block","enum":["VerticalAlignTop","VerticalAlignMiddle","VerticalAlignBottom"],"example":"VerticalAlignTop","type":"string"}},"type":"object"},"object.CreateObjectRequest":{"properties":{"body":{"description":"The body of the object","example":"This is the body of the object. Markdown syntax is supported here.","type":"string"},"description":{"description":"The description of the object","example":"This is a description of the object.","type":"string"},"icon":{"description":"The icon of the object","example":"📄","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object_type_unique_key":{"description":"The unique key of the object type","example":"ot-page","type":"string"},"source":{"description":"The source url, only applicable for bookmarks","example":"https://bookmark-source.com","type":"string"},"template_id":{"description":"The id of the template to use","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"}},"type":"object"},"object.Detail":{"properties":{"details":{"additionalProperties":{},"description":"The details","type":"object"},"id":{"description":"The id of the detail","enum":["last_modified_date","last_modified_by","created_date","created_by","last_opened_date","tags"],"example":"last_modified_date","type":"string"}},"type":"object"},"object.File":{"description":"The file of the block, if applicable","properties":{"added_at":{"description":"The added at of the file","type":"integer"},"hash":{"description":"The hash of the file","type":"string"},"mime":{"description":"The mime of the file","type":"string"},"name":{"description":"The name of the file","type":"string"},"size":{"description":"The size of the file","type":"integer"},"state":{"description":"The state of the file","type":"string"},"style":{"description":"The style of the file","type":"string"},"target_object_id":{"description":"The target object id of the file","type":"string"},"type":{"description":"The type of the file","type":"string"}},"type":"object"},"object.Object":{"description":"The object","properties":{"blocks":{"description":"The blocks of the object","items":{"$ref":"#/components/schemas/object.Block"},"type":"array","uniqueItems":false},"details":{"description":"The details of the object","items":{"$ref":"#/components/schemas/object.Detail"},"type":"array","uniqueItems":false},"icon":{"description":"The icon of the object","example":"📄","type":"string"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"root_id":{"description":"The id of the object's root","example":"bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u","type":"string"},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/object.Type"}},"type":"object"},"object.ObjectResponse":{"properties":{"object":{"$ref":"#/components/schemas/object.Object"}},"type":"object"},"object.Relation":{"description":"The relation of the block, if applicable","properties":{"id":{"type":"string"}},"type":"object"},"object.Template":{"description":"The template","properties":{"icon":{"description":"The icon of the template","example":"📄","type":"string"},"id":{"description":"The id of the template","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"},"name":{"description":"The name of the template","example":"My template","type":"string"},"object":{"description":"The data model of the object","example":"template","type":"string"}},"type":"object"},"object.TemplateResponse":{"properties":{"template":{"$ref":"#/components/schemas/object.Template"}},"type":"object"},"object.Text":{"description":"The text of the block, if applicable","properties":{"checked":{"description":"Whether the text is checked","example":true,"type":"boolean"},"color":{"description":"The color of the text","example":"red","type":"string"},"icon":{"description":"The icon of the text","example":"📄","type":"string"},"style":{"description":"The style of the text","enum":["Paragraph","Header1","Header2","Header3","Header4","Quote","Code","Title","Checkbox","Marked","Numbered","Toggle","Description","Callout"],"example":"Paragraph","type":"string"},"text":{"description":"The text","example":"Some text...","type":"string"}},"type":"object"},"object.Type":{"description":"The type of the object","properties":{"icon":{"description":"The icon of the type","example":"📄","type":"string"},"id":{"description":"The id of the type","example":"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu","type":"string"},"name":{"description":"The name of the type","example":"Page","type":"string"},"object":{"description":"The data model of the object","example":"type","type":"string"},"recommended_layout":{"description":"The recommended layout of the type","example":"todo","type":"string"},"unique_key":{"description":"The unique key of the type","example":"ot-page","type":"string"}},"type":"object"},"object.TypeResponse":{"properties":{"type":{"$ref":"#/components/schemas/object.Type"}},"type":"object"},"pagination.PaginatedResponse-object_Object":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Object"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-object_Template":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Template"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-object_Type":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Type"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-space_Member":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/space.Member"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-space_Space":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/space.Space"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginationMeta":{"description":"The pagination metadata for the response","properties":{"has_more":{"description":"Indicates if there are more items available beyond the current result set","example":true,"type":"boolean"},"limit":{"description":"The maximum number of items returned in the result set","example":100,"type":"integer"},"offset":{"description":"The number of items skipped before starting to collect the result set","example":0,"type":"integer"},"total":{"description":"The total number of items available for the endpoint","example":1024,"type":"integer"}},"type":"object"},"search.SearchRequest":{"properties":{"query":{"description":"The search term to look for in object names and snippets","example":"test","type":"string"},"sort":{"$ref":"#/components/schemas/search.SortOptions"},"types":{"description":"The types of objects to search for, specified by unique key or ID","example":["ot-note","ot-page","ot-678043f0cda9133be777049f","bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"search.SortOptions":{"description":"The sorting criteria and direction for the search results","properties":{"direction":{"default":"desc","description":"The direction to sort the search results","enum":["asc","desc"],"type":"string"},"timestamp":{"default":"last_modified_date","description":"The timestamp to sort the search results by","enum":["created_date","last_modified_date","last_opened_date"],"type":"string"}},"type":"object"},"space.CreateSpaceRequest":{"properties":{"name":{"description":"The name of the space","example":"New Space","type":"string"}},"type":"object"},"space.Member":{"description":"The member","properties":{"global_name":{"description":"The global name of the member in the network","example":"john.any","type":"string"},"icon":{"description":"The icon of the member","example":"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100","type":"string"},"id":{"description":"The profile object id of the member","example":"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ","type":"string"},"identity":{"description":"The identity of the member in the network","example":"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ","type":"string"},"name":{"description":"The name of the member","example":"John Doe","type":"string"},"object":{"description":"The data model of the object","example":"member","type":"string"},"role":{"description":"The role of the member","enum":["Reader","Writer","Owner","NoPermission"],"example":"Owner","type":"string"}},"type":"object"},"space.MemberResponse":{"properties":{"member":{"$ref":"#/components/schemas/space.Member"}},"type":"object"},"space.Space":{"description":"The space","properties":{"account_space_id":{"description":"The id of the account space","example":"bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1","type":"string"},"analytics_id":{"description":"The analytics id of the account","example":"624aecdd-4797-4611-9d61-a2ae5f53cf1c","type":"string"},"archive_object_id":{"description":"The id of the archive object","example":"bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri","type":"string"},"device_id":{"description":"The id of the device","example":"12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF","type":"string"},"gateway_url":{"description":"The gateway url to serve files and media","example":"http://127.0.0.1:31006","type":"string"},"home_object_id":{"description":"The id of the home object","example":"bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya","type":"string"},"icon":{"description":"The icon of the space","example":"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay","type":"string"},"id":{"description":"The id of the space","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"local_storage_path":{"description":"The local storage path of the account","example":"/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha","type":"string"},"marketplace_workspace_id":{"description":"The id of the marketplace workspace","example":"_anytype_marketplace","type":"string"},"name":{"description":"The name of the space","example":"My Space","type":"string"},"network_id":{"description":"The network id of the space","example":"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU","type":"string"},"object":{"description":"The data model of the object","example":"space","type":"string"},"profile_object_id":{"description":"The id of the profile object","example":"bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4","type":"string"},"space_view_id":{"description":"The id of the space view","example":"bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy","type":"string"},"tech_space_id":{"description":"The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself","example":"bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1","type":"string"},"timezone":{"description":"The timezone of the account","example":"","type":"string"},"widgets_id":{"description":"The id of the widgets","example":"bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva","type":"string"},"workspace_object_id":{"description":"The id of the workspace object","example":"bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y","type":"string"}},"type":"object"},"space.SpaceResponse":{"properties":{"space":{"$ref":"#/components/schemas/space.Space"}},"type":"object"},"util.ForbiddenError":{"properties":{"error":{"properties":{"message":{"example":"Forbidden","type":"string"}},"type":"object"}},"type":"object"},"util.NotFoundError":{"properties":{"error":{"properties":{"message":{"example":"Resource not found","type":"string"}},"type":"object"}},"type":"object"},"util.RateLimitError":{"properties":{"error":{"properties":{"message":{"example":"Rate limit exceeded","type":"string"}},"type":"object"}},"type":"object"},"util.ServerError":{"properties":{"error":{"properties":{"message":{"example":"Internal server error","type":"string"}},"type":"object"}},"type":"object"},"util.UnauthorizedError":{"properties":{"error":{"properties":{"message":{"example":"Unauthorized","type":"string"}},"type":"object"}},"type":"object"},"util.ValidationError":{"properties":{"error":{"properties":{"message":{"example":"Bad request","type":"string"}},"type":"object"}},"type":"object"}},"securitySchemes":{"bearerauth":{"bearerFormat":"JWT","scheme":"bearer","type":"http"}}}, + "info": {"contact":{"email":"support@anytype.io","name":"Anytype Support","url":"https://anytype.io/contact"},"description":"This API allows interaction with Anytype resources such as spaces, objects and types.","license":{"name":"Any Source Available License 1.0","url":"https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md"},"termsOfService":"https://anytype.io/terms_of_use","title":"Anytype API","version":"1.0"}, + "externalDocs": {"description":"OpenAPI","url":"https://swagger.io/resources/open-api/"}, + "paths": {"/auth/display_code":{"post":{"parameters":[{"description":"App name requesting the challenge","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.DisplayCodeResponse"}}},"description":"Challenge ID"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["auth"]}},"/auth/token":{"post":{"parameters":[{"description":"Challenge ID","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.TokenResponse"}}},"description":"Authentication token"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Retrieve token","tags":["auth"]}},"/search":{"post":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["search"]}},"/spaces":{"get":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Space"}}},"description":"List of spaces"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["spaces"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.CreateSpaceRequest"}}},"description":"Space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space created successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["spaces"]}},"/spaces/{space_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["spaces"]}},"/spaces/{space_id}/members":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Member"}}},"description":"List of members"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["spaces"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.MemberResponse"}}},"description":"Member"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["spaces"]}},"/spaces/{space_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["objects"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.CreateObjectRequest"}}},"description":"Object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["objects"]},"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The requested object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}/export/{format}":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"Export format","in":"path","name":"format","required":true,"schema":{"enum":["markdown","protobuf"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/export.ObjectExportResponse"}}},"description":"Object exported successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Export object","tags":["export"]}},"/spaces/{space_id}/search":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["search"]}},"/spaces/{space_id}/types":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Type"}}},"description":"List of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["types"]}},"/spaces/{space_id}/types/{type_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Template"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"Template ID","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["types"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["lists"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"List of object IDs","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["lists"]}}}, + "openapi": "3.1.0", + "servers": [ + {"url":"localhost:31009/v1"} + ] } \ No newline at end of file diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index c4dfe63d13..deb31aec21 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -1,630 +1,626 @@ -basePath: /v1 -definitions: - auth.DisplayCodeResponse: - properties: - challenge_id: - description: The challenge id associated with the displayed code and needed - to solve the challenge for token - example: 67647f5ecda913e9a2e11b26 - type: string - type: object - auth.TokenResponse: - properties: - app_key: - description: The permanent app key - example: zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6= - type: string - session_token: - description: The ephemeral session token - example: eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII - type: string - type: object - export.ObjectExportResponse: - properties: - path: - description: The path the object was exported to - example: /path/to/export - type: string - type: object - object.Block: - properties: - align: - description: The alignment of the block - enum: - - AlignLeft - - AlignCenter - - AlignRight - - AlignJustify - example: AlignLeft - type: string - background_color: - description: The background color of the block - example: red - type: string - children_ids: - description: The ids of the block's children - example: - - '[''6797ce8ecda913cde14b02dc'']' - items: - type: string - type: array - file: - allOf: - - $ref: '#/definitions/object.File' - description: The file of the block, if applicable - id: - description: The id of the block - example: 64394517de52ad5acb89c66c - type: string - relation: - allOf: - - $ref: '#/definitions/object.Relation' - description: The relation of the block, if applicable - text: - allOf: - - $ref: '#/definitions/object.Text' - description: The text of the block, if applicable - vertical_align: - description: The vertical alignment of the block - enum: - - VerticalAlignTop - - VerticalAlignMiddle - - VerticalAlignBottom - example: VerticalAlignTop - type: string - type: object - object.CreateObjectRequest: - properties: - body: - description: The body of the object - example: This is the body of the object. Markdown syntax is supported here. - type: string - description: - description: The description of the object - example: This is a description of the object. - type: string - icon: - description: The icon of the object - example: "\U0001F4C4" - type: string - name: - description: The name of the object - example: My object - type: string - object_type_unique_key: - description: The unique key of the object type - example: ot-page - type: string - source: - description: The source url, only applicable for bookmarks - example: https://bookmark-source.com - type: string - template_id: - description: The id of the template to use - example: bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge - type: string - type: object - object.Detail: - properties: - details: - additionalProperties: true - description: The details - type: object - id: - description: The id of the detail - enum: - - last_modified_date - - last_modified_by - - created_date - - created_by - - last_opened_date - - tags - example: last_modified_date - type: string - type: object - object.File: - properties: - added_at: - description: The added at of the file - type: integer - hash: - description: The hash of the file - type: string - mime: - description: The mime of the file - type: string - name: - description: The name of the file - type: string - size: - description: The size of the file - type: integer - state: - description: The state of the file - type: string - style: - description: The style of the file - type: string - target_object_id: - description: The target object id of the file - type: string - type: - description: The type of the file - type: string - type: object - object.Object: - properties: - blocks: - description: The blocks of the object - items: - $ref: '#/definitions/object.Block' - type: array - details: - description: The details of the object - items: - $ref: '#/definitions/object.Detail' - type: array - icon: - description: The icon of the object - example: "\U0001F4C4" - type: string - id: - description: The id of the object - example: bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ - type: string - layout: - description: The layout of the object - example: basic - type: string - name: - description: The name of the object - example: My object - type: string - object: - description: The data model of the object - example: object - type: string - root_id: - description: The id of the object's root - example: bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u - type: string - snippet: - description: The snippet of the object, especially important for notes as - they don't have a name - example: The beginning of the object body... - type: string - space_id: - description: The id of the space the object is in - example: bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1 - type: string - type: - allOf: - - $ref: '#/definitions/object.Type' - description: The type of the object - type: object - object.ObjectResponse: - properties: - object: - allOf: - - $ref: '#/definitions/object.Object' - description: The object - type: object - object.Relation: - properties: - id: - type: string - type: object - object.Template: - properties: - icon: - description: The icon of the template - example: "\U0001F4C4" - type: string - id: - description: The id of the template - example: bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge - type: string - name: - description: The name of the template - example: My template - type: string - object: - description: The data model of the object - example: template - type: string - type: object - object.TemplateResponse: - properties: - template: - allOf: - - $ref: '#/definitions/object.Template' - description: The template - type: object - object.Text: - properties: - checked: - description: Whether the text is checked - example: true - type: boolean - color: - description: The color of the text - example: red - type: string - icon: - description: The icon of the text - example: "\U0001F4C4" - type: string - style: - description: The style of the text - enum: - - Paragraph - - Header1 - - Header2 - - Header3 - - Header4 - - Quote - - Code - - Title - - Checkbox - - Marked - - Numbered - - Toggle - - Description - - Callout - example: Paragraph - type: string - text: - description: The text - example: Some text... - type: string - type: object - object.Type: - properties: - icon: - description: The icon of the type - example: "\U0001F4C4" - type: string - id: - description: The id of the type - example: bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu - type: string - name: - description: The name of the type - example: Page - type: string - object: - description: The data model of the object - example: type - type: string - recommended_layout: - description: The recommended layout of the type - example: todo - type: string - unique_key: - description: The unique key of the type - example: ot-page - type: string - type: object - object.TypeResponse: - properties: - type: - allOf: - - $ref: '#/definitions/object.Type' - description: The type - type: object - pagination.PaginatedResponse-object_Object: - properties: - data: - description: The list of items in the current result set - items: - $ref: '#/definitions/object.Object' - type: array - pagination: - allOf: - - $ref: '#/definitions/pagination.PaginationMeta' - description: The pagination metadata for the response - type: object - pagination.PaginatedResponse-object_Template: - properties: - data: - description: The list of items in the current result set - items: - $ref: '#/definitions/object.Template' - type: array - pagination: - allOf: - - $ref: '#/definitions/pagination.PaginationMeta' - description: The pagination metadata for the response - type: object - pagination.PaginatedResponse-object_Type: - properties: - data: - description: The list of items in the current result set - items: - $ref: '#/definitions/object.Type' - type: array - pagination: - allOf: - - $ref: '#/definitions/pagination.PaginationMeta' - description: The pagination metadata for the response - type: object - pagination.PaginatedResponse-space_Member: - properties: - data: - description: The list of items in the current result set - items: - $ref: '#/definitions/space.Member' - type: array - pagination: - allOf: - - $ref: '#/definitions/pagination.PaginationMeta' - description: The pagination metadata for the response - type: object - pagination.PaginatedResponse-space_Space: - properties: - data: - description: The list of items in the current result set - items: - $ref: '#/definitions/space.Space' - type: array - pagination: - allOf: - - $ref: '#/definitions/pagination.PaginationMeta' - description: The pagination metadata for the response - type: object - pagination.PaginationMeta: - properties: - has_more: - description: Indicates if there are more items available beyond the current - result set - example: true - type: boolean - limit: - description: The maximum number of items returned in the result set - example: 100 - type: integer - offset: - description: The number of items skipped before starting to collect the result - set - example: 0 - type: integer - total: - description: The total number of items available for the endpoint - example: 1024 - type: integer - type: object - search.SearchRequest: - properties: - query: - description: The search term to look for in object names and snippets - example: test - type: string - sort: - allOf: - - $ref: '#/definitions/search.SortOptions' - description: The sorting criteria and direction for the search results - types: - description: The types of objects to search for, specified by unique key or - ID - example: - - ot-note - - ot-page - - ot-678043f0cda9133be777049f - - bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q - items: - type: string - type: array - type: object - search.SortOptions: - properties: - direction: - default: desc - description: The direction to sort the search results - enum: - - asc - - desc - type: string - timestamp: - default: last_modified_date - description: The timestamp to sort the search results by - enum: - - created_date - - last_modified_date - - last_opened_date - type: string - type: object - space.CreateSpaceRequest: - properties: - name: - description: The name of the space - example: New Space - type: string - type: object - space.Member: - properties: - global_name: - description: The global name of the member in the network - example: john.any - type: string - icon: - description: The icon of the member - example: http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100 - type: string - id: - description: The profile object id of the member - example: _participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ - type: string - identity: - description: The identity of the member in the network - example: AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ - type: string - name: - description: The name of the member - example: John Doe - type: string - object: - description: The data model of the object - example: member - type: string - role: - description: The role of the member - enum: - - Reader - - Writer - - Owner - - NoPermission - example: Owner - type: string - type: object - space.MemberResponse: - properties: - member: - allOf: - - $ref: '#/definitions/space.Member' - description: The member - type: object - space.Space: - properties: - account_space_id: - description: The id of the account space - example: bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1 - type: string - analytics_id: - description: The analytics id of the account - example: 624aecdd-4797-4611-9d61-a2ae5f53cf1c - type: string - archive_object_id: - description: The id of the archive object - example: bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri - type: string - device_id: - description: The id of the device - example: 12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF - type: string - gateway_url: - description: The gateway url to serve files and media - example: http://127.0.0.1:31006 - type: string - home_object_id: - description: The id of the home object - example: bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya - type: string - icon: - description: The icon of the space - example: http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay - type: string - id: - description: The id of the space - example: bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1 - type: string - local_storage_path: - description: The local storage path of the account - example: /Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha - type: string - marketplace_workspace_id: - description: The id of the marketplace workspace - example: _anytype_marketplace - type: string - name: - description: The name of the space - example: My Space - type: string - network_id: - description: The network id of the space - example: N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU - type: string - object: - description: The data model of the object - example: space - type: string - profile_object_id: - description: The id of the profile object - example: bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4 - type: string - space_view_id: - description: The id of the space view - example: bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy - type: string - tech_space_id: - description: The id of tech space, where objects outside of user's actual - spaces are stored, e.g. spaces itself - example: bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1 - type: string - timezone: - description: The timezone of the account - example: "" - type: string - widgets_id: - description: The id of the widgets - example: bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva - type: string - workspace_object_id: - description: The id of the workspace object - example: bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y - type: string - type: object - space.SpaceResponse: - properties: - space: - allOf: - - $ref: '#/definitions/space.Space' - description: The space - type: object - util.ForbiddenError: - properties: - error: - properties: - message: - example: Forbidden - type: string - type: object - type: object - util.NotFoundError: - properties: - error: - properties: - message: - example: Resource not found - type: string - type: object - type: object - util.RateLimitError: - properties: - error: - properties: - message: - example: Rate limit exceeded - type: string - type: object - type: object - util.ServerError: - properties: - error: - properties: - message: - example: Internal server error - type: string - type: object - type: object - util.UnauthorizedError: - properties: - error: - properties: - message: - example: Unauthorized +components: + schemas: + auth.DisplayCodeResponse: + properties: + challenge_id: + description: The challenge id associated with the displayed code and needed + to solve the challenge for token + example: 67647f5ecda913e9a2e11b26 + type: string + type: object + auth.TokenResponse: + properties: + app_key: + description: The permanent app key + example: zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6= + type: string + session_token: + description: The ephemeral session token + example: eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII + type: string + type: object + export.ObjectExportResponse: + properties: + path: + description: The path the object was exported to + example: /path/to/export + type: string + type: object + object.Block: + properties: + align: + description: The alignment of the block + enum: + - AlignLeft + - AlignCenter + - AlignRight + - AlignJustify + example: AlignLeft + type: string + background_color: + description: The background color of the block + example: red + type: string + children_ids: + description: The ids of the block's children + example: + - '[''6797ce8ecda913cde14b02dc'']' + items: type: string - type: object - type: object - util.ValidationError: - properties: - error: - properties: - message: - example: Bad request + type: array + uniqueItems: false + file: + $ref: '#/components/schemas/object.File' + id: + description: The id of the block + example: 64394517de52ad5acb89c66c + type: string + relation: + $ref: '#/components/schemas/object.Relation' + text: + $ref: '#/components/schemas/object.Text' + vertical_align: + description: The vertical alignment of the block + enum: + - VerticalAlignTop + - VerticalAlignMiddle + - VerticalAlignBottom + example: VerticalAlignTop + type: string + type: object + object.CreateObjectRequest: + properties: + body: + description: The body of the object + example: This is the body of the object. Markdown syntax is supported here. + type: string + description: + description: The description of the object + example: This is a description of the object. + type: string + icon: + description: The icon of the object + example: "\U0001F4C4" + type: string + name: + description: The name of the object + example: My object + type: string + object_type_unique_key: + description: The unique key of the object type + example: ot-page + type: string + source: + description: The source url, only applicable for bookmarks + example: https://bookmark-source.com + type: string + template_id: + description: The id of the template to use + example: bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge + type: string + type: object + object.Detail: + properties: + details: + additionalProperties: {} + description: The details + type: object + id: + description: The id of the detail + enum: + - last_modified_date + - last_modified_by + - created_date + - created_by + - last_opened_date + - tags + example: last_modified_date + type: string + type: object + object.File: + description: The file of the block, if applicable + properties: + added_at: + description: The added at of the file + type: integer + hash: + description: The hash of the file + type: string + mime: + description: The mime of the file + type: string + name: + description: The name of the file + type: string + size: + description: The size of the file + type: integer + state: + description: The state of the file + type: string + style: + description: The style of the file + type: string + target_object_id: + description: The target object id of the file + type: string + type: + description: The type of the file + type: string + type: object + object.Object: + description: The object + properties: + blocks: + description: The blocks of the object + items: + $ref: '#/components/schemas/object.Block' + type: array + uniqueItems: false + details: + description: The details of the object + items: + $ref: '#/components/schemas/object.Detail' + type: array + uniqueItems: false + icon: + description: The icon of the object + example: "\U0001F4C4" + type: string + id: + description: The id of the object + example: bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ + type: string + layout: + description: The layout of the object + example: basic + type: string + name: + description: The name of the object + example: My object + type: string + object: + description: The data model of the object + example: object + type: string + root_id: + description: The id of the object's root + example: bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u + type: string + snippet: + description: The snippet of the object, especially important for notes as + they don't have a name + example: The beginning of the object body... + type: string + space_id: + description: The id of the space the object is in + example: bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1 + type: string + type: + $ref: '#/components/schemas/object.Type' + type: object + object.ObjectResponse: + properties: + object: + $ref: '#/components/schemas/object.Object' + type: object + object.Relation: + description: The relation of the block, if applicable + properties: + id: + type: string + type: object + object.Template: + description: The template + properties: + icon: + description: The icon of the template + example: "\U0001F4C4" + type: string + id: + description: The id of the template + example: bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge + type: string + name: + description: The name of the template + example: My template + type: string + object: + description: The data model of the object + example: template + type: string + type: object + object.TemplateResponse: + properties: + template: + $ref: '#/components/schemas/object.Template' + type: object + object.Text: + description: The text of the block, if applicable + properties: + checked: + description: Whether the text is checked + example: true + type: boolean + color: + description: The color of the text + example: red + type: string + icon: + description: The icon of the text + example: "\U0001F4C4" + type: string + style: + description: The style of the text + enum: + - Paragraph + - Header1 + - Header2 + - Header3 + - Header4 + - Quote + - Code + - Title + - Checkbox + - Marked + - Numbered + - Toggle + - Description + - Callout + example: Paragraph + type: string + text: + description: The text + example: Some text... + type: string + type: object + object.Type: + description: The type of the object + properties: + icon: + description: The icon of the type + example: "\U0001F4C4" + type: string + id: + description: The id of the type + example: bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu + type: string + name: + description: The name of the type + example: Page + type: string + object: + description: The data model of the object + example: type + type: string + recommended_layout: + description: The recommended layout of the type + example: todo + type: string + unique_key: + description: The unique key of the type + example: ot-page + type: string + type: object + object.TypeResponse: + properties: + type: + $ref: '#/components/schemas/object.Type' + type: object + pagination.PaginatedResponse-object_Object: + properties: + data: + description: The list of items in the current result set + items: + $ref: '#/components/schemas/object.Object' + type: array + uniqueItems: false + pagination: + $ref: '#/components/schemas/pagination.PaginationMeta' + type: object + pagination.PaginatedResponse-object_Template: + properties: + data: + description: The list of items in the current result set + items: + $ref: '#/components/schemas/object.Template' + type: array + uniqueItems: false + pagination: + $ref: '#/components/schemas/pagination.PaginationMeta' + type: object + pagination.PaginatedResponse-object_Type: + properties: + data: + description: The list of items in the current result set + items: + $ref: '#/components/schemas/object.Type' + type: array + uniqueItems: false + pagination: + $ref: '#/components/schemas/pagination.PaginationMeta' + type: object + pagination.PaginatedResponse-space_Member: + properties: + data: + description: The list of items in the current result set + items: + $ref: '#/components/schemas/space.Member' + type: array + uniqueItems: false + pagination: + $ref: '#/components/schemas/pagination.PaginationMeta' + type: object + pagination.PaginatedResponse-space_Space: + properties: + data: + description: The list of items in the current result set + items: + $ref: '#/components/schemas/space.Space' + type: array + uniqueItems: false + pagination: + $ref: '#/components/schemas/pagination.PaginationMeta' + type: object + pagination.PaginationMeta: + description: The pagination metadata for the response + properties: + has_more: + description: Indicates if there are more items available beyond the current + result set + example: true + type: boolean + limit: + description: The maximum number of items returned in the result set + example: 100 + type: integer + offset: + description: The number of items skipped before starting to collect the + result set + example: 0 + type: integer + total: + description: The total number of items available for the endpoint + example: 1024 + type: integer + type: object + search.SearchRequest: + properties: + query: + description: The search term to look for in object names and snippets + example: test + type: string + sort: + $ref: '#/components/schemas/search.SortOptions' + types: + description: The types of objects to search for, specified by unique key + or ID + example: + - ot-note + - ot-page + - ot-678043f0cda9133be777049f + - bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q + items: type: string - type: object - type: object -host: localhost:31009 + type: array + uniqueItems: false + type: object + search.SortOptions: + description: The sorting criteria and direction for the search results + properties: + direction: + default: desc + description: The direction to sort the search results + enum: + - asc + - desc + type: string + timestamp: + default: last_modified_date + description: The timestamp to sort the search results by + enum: + - created_date + - last_modified_date + - last_opened_date + type: string + type: object + space.CreateSpaceRequest: + properties: + name: + description: The name of the space + example: New Space + type: string + type: object + space.Member: + description: The member + properties: + global_name: + description: The global name of the member in the network + example: john.any + type: string + icon: + description: The icon of the member + example: http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100 + type: string + id: + description: The profile object id of the member + example: _participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ + type: string + identity: + description: The identity of the member in the network + example: AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ + type: string + name: + description: The name of the member + example: John Doe + type: string + object: + description: The data model of the object + example: member + type: string + role: + description: The role of the member + enum: + - Reader + - Writer + - Owner + - NoPermission + example: Owner + type: string + type: object + space.MemberResponse: + properties: + member: + $ref: '#/components/schemas/space.Member' + type: object + space.Space: + description: The space + properties: + account_space_id: + description: The id of the account space + example: bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1 + type: string + analytics_id: + description: The analytics id of the account + example: 624aecdd-4797-4611-9d61-a2ae5f53cf1c + type: string + archive_object_id: + description: The id of the archive object + example: bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri + type: string + device_id: + description: The id of the device + example: 12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF + type: string + gateway_url: + description: The gateway url to serve files and media + example: http://127.0.0.1:31006 + type: string + home_object_id: + description: The id of the home object + example: bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya + type: string + icon: + description: The icon of the space + example: http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay + type: string + id: + description: The id of the space + example: bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1 + type: string + local_storage_path: + description: The local storage path of the account + example: /Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha + type: string + marketplace_workspace_id: + description: The id of the marketplace workspace + example: _anytype_marketplace + type: string + name: + description: The name of the space + example: My Space + type: string + network_id: + description: The network id of the space + example: N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU + type: string + object: + description: The data model of the object + example: space + type: string + profile_object_id: + description: The id of the profile object + example: bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4 + type: string + space_view_id: + description: The id of the space view + example: bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy + type: string + tech_space_id: + description: The id of tech space, where objects outside of user's actual + spaces are stored, e.g. spaces itself + example: bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1 + type: string + timezone: + description: The timezone of the account + example: "" + type: string + widgets_id: + description: The id of the widgets + example: bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva + type: string + workspace_object_id: + description: The id of the workspace object + example: bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y + type: string + type: object + space.SpaceResponse: + properties: + space: + $ref: '#/components/schemas/space.Space' + type: object + util.ForbiddenError: + properties: + error: + properties: + message: + example: Forbidden + type: string + type: object + type: object + util.NotFoundError: + properties: + error: + properties: + message: + example: Resource not found + type: string + type: object + type: object + util.RateLimitError: + properties: + error: + properties: + message: + example: Rate limit exceeded + type: string + type: object + type: object + util.ServerError: + properties: + error: + properties: + message: + example: Internal server error + type: string + type: object + type: object + util.UnauthorizedError: + properties: + error: + properties: + message: + example: Unauthorized + type: string + type: object + type: object + util.ValidationError: + properties: + error: + properties: + message: + example: Bad request + type: string + type: object + type: object + securitySchemes: + bearerauth: + bearerFormat: JWT + scheme: bearer + type: http +externalDocs: + description: OpenAPI + url: https://swagger.io/resources/open-api/ info: contact: email: support@anytype.io @@ -638,852 +634,1030 @@ info: termsOfService: https://anytype.io/terms_of_use title: Anytype API version: "1.0" +openapi: 3.1.0 paths: /auth/display_code: post: - consumes: - - application/json parameters: - description: App name requesting the challenge in: query name: app_name required: true - type: string - produces: - - application/json + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/auth.DisplayCodeResponse' description: Challenge ID - schema: - $ref: '#/definitions/auth.DisplayCodeResponse' "400": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ValidationError' description: Invalid input - schema: - $ref: '#/definitions/util.ValidationError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' summary: Start new challenge tags: - auth /auth/token: post: - consumes: - - application/json parameters: - description: Challenge ID in: query name: challenge_id required: true - type: string + schema: + type: string - description: 4-digit code retrieved from Anytype Desktop app in: query name: code required: true - type: string - produces: - - application/json + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/auth.TokenResponse' description: Authentication token - schema: - $ref: '#/definitions/auth.TokenResponse' "400": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ValidationError' description: Invalid input - schema: - $ref: '#/definitions/util.ValidationError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' summary: Retrieve token tags: - auth /search: post: - consumes: - - application/json parameters: - - default: 0 - description: The number of items to skip before starting to collect the result + - description: The number of items to skip before starting to collect the result set in: query name: offset - type: integer - - default: 100 - description: The number of items to return + schema: + default: 0 + type: integer + - description: The number of items to return in: query - maximum: 1000 name: limit - type: integer - - description: Search parameters - in: body - name: request - required: true schema: - $ref: '#/definitions/search.SearchRequest' - produces: - - application/json + default: 100 + maximum: 1000 + type: integer + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/search.SearchRequest' + description: Search parameters + required: true responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-object_Object' description: List of objects - schema: - $ref: '#/definitions/pagination.PaginatedResponse-object_Object' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Search objects across all spaces tags: - search /spaces: get: - consumes: - - application/json parameters: - - default: 0 - description: The number of items to skip before starting to collect the result + - description: The number of items to skip before starting to collect the result set in: query name: offset - type: integer - - default: 100 - description: The number of items to return + schema: + default: 0 + type: integer + - description: The number of items to return in: query - maximum: 1000 name: limit - type: integer - produces: - - application/json + schema: + default: 100 + maximum: 1000 + type: integer responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-space_Space' description: List of spaces - schema: - $ref: '#/definitions/pagination.PaginatedResponse-space_Space' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: List spaces tags: - spaces post: - consumes: - - application/json - parameters: - - description: Space to create - in: body - name: name + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/space.CreateSpaceRequest' + description: Space to create required: true - schema: - $ref: '#/definitions/space.CreateSpaceRequest' - produces: - - application/json responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/space.SpaceResponse' description: Space created successfully - schema: - $ref: '#/definitions/space.SpaceResponse' "400": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ValidationError' description: Bad request - schema: - $ref: '#/definitions/util.ValidationError' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "423": + content: + application/json: + schema: + $ref: '#/components/schemas/util.RateLimitError' description: Rate limit exceeded - schema: - $ref: '#/definitions/util.RateLimitError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Create space tags: - spaces /spaces/{space_id}: get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string - produces: - - application/json + schema: + type: string responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/space.SpaceResponse' description: Space - schema: - $ref: '#/definitions/space.SpaceResponse' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Space not found - schema: - $ref: '#/definitions/util.NotFoundError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Get space tags: - spaces /spaces/{space_id}/members: get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string - - default: 0 - description: The number of items to skip before starting to collect the result + schema: + type: string + - description: The number of items to skip before starting to collect the result set in: query name: offset - type: integer - - default: 100 - description: The number of items to return + schema: + default: 0 + type: integer + - description: The number of items to return in: query - maximum: 1000 name: limit - type: integer - produces: - - application/json + schema: + default: 100 + maximum: 1000 + type: integer responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-space_Member' description: List of members - schema: - $ref: '#/definitions/pagination.PaginatedResponse-space_Member' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: List members tags: - spaces /spaces/{space_id}/members/{member_id}: get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: Member ID in: path name: member_id required: true - type: string - produces: - - application/json + schema: + type: string responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/space.MemberResponse' description: Member - schema: - $ref: '#/definitions/space.MemberResponse' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Member not found - schema: - $ref: '#/definitions/util.NotFoundError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Get member tags: - spaces /spaces/{space_id}/objects: get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string - - default: 0 - description: The number of items to skip before starting to collect the result + schema: + type: string + - description: The number of items to skip before starting to collect the result set in: query name: offset - type: integer - - default: 100 - description: The number of items to return + schema: + default: 0 + type: integer + - description: The number of items to return in: query - maximum: 1000 name: limit - type: integer - produces: - - application/json + schema: + default: 100 + maximum: 1000 + type: integer responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-object_Object' description: List of objects - schema: - $ref: '#/definitions/pagination.PaginatedResponse-object_Object' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: List objects tags: - objects post: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string - - description: Object to create - in: body - name: object - required: true schema: - $ref: '#/definitions/object.CreateObjectRequest' - produces: - - application/json + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/object.CreateObjectRequest' + description: Object to create + required: true responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/object.ObjectResponse' description: The created object - schema: - $ref: '#/definitions/object.ObjectResponse' "400": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ValidationError' description: Bad request - schema: - $ref: '#/definitions/util.ValidationError' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "423": + content: + application/json: + schema: + $ref: '#/components/schemas/util.RateLimitError' description: Rate limit exceeded - schema: - $ref: '#/definitions/util.RateLimitError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Create object tags: - objects /spaces/{space_id}/objects/{object_id}: delete: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: Object ID in: path name: object_id required: true - type: string - produces: - - application/json + schema: + type: string responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/object.ObjectResponse' description: The deleted object - schema: - $ref: '#/definitions/object.ObjectResponse' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "403": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ForbiddenError' description: Forbidden - schema: - $ref: '#/definitions/util.ForbiddenError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Resource not found - schema: - $ref: '#/definitions/util.NotFoundError' "423": + content: + application/json: + schema: + $ref: '#/components/schemas/util.RateLimitError' description: Rate limit exceeded - schema: - $ref: '#/definitions/util.RateLimitError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Delete object tags: - objects get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: Object ID in: path name: object_id required: true - type: string - produces: - - application/json + schema: + type: string responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/object.ObjectResponse' description: The requested object - schema: - $ref: '#/definitions/object.ObjectResponse' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Resource not found - schema: - $ref: '#/definitions/util.NotFoundError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Get object tags: - objects /spaces/{space_id}/objects/{object_id}/export/{format}: post: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: Object ID in: path name: object_id required: true - type: string + schema: + type: string - description: Export format - enum: - - markdown - - protobuf in: path name: format required: true - type: string - produces: - - application/json + schema: + enum: + - markdown + - protobuf + type: string + requestBody: + content: + application/json: + schema: + type: object responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/export.ObjectExportResponse' description: Object exported successfully - schema: - $ref: '#/definitions/export.ObjectExportResponse' "400": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ValidationError' description: Bad request - schema: - $ref: '#/definitions/util.ValidationError' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Export object tags: - export /spaces/{space_id}/search: post: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string - - default: 0 - description: The number of items to skip before starting to collect the result + schema: + type: string + - description: The number of items to skip before starting to collect the result set in: query name: offset - type: integer - - default: 100 - description: The number of items to return + schema: + default: 0 + type: integer + - description: The number of items to return in: query - maximum: 1000 name: limit - type: integer - - description: Search parameters - in: body - name: request - required: true schema: - $ref: '#/definitions/search.SearchRequest' - produces: - - application/json + default: 100 + maximum: 1000 + type: integer + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/search.SearchRequest' + description: Search parameters + required: true responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-object_Object' description: List of objects - schema: - $ref: '#/definitions/pagination.PaginatedResponse-object_Object' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Search objects within a space tags: - search /spaces/{space_id}/types: get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string - - default: 0 - description: The number of items to skip before starting to collect the result + schema: + type: string + - description: The number of items to skip before starting to collect the result set in: query name: offset - type: integer - - default: 100 - description: The number of items to return + schema: + default: 0 + type: integer + - description: The number of items to return in: query - maximum: 1000 name: limit - type: integer - produces: - - application/json + schema: + default: 100 + maximum: 1000 + type: integer responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-object_Type' description: List of types - schema: - $ref: '#/definitions/pagination.PaginatedResponse-object_Type' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: List types tags: - types /spaces/{space_id}/types/{type_id}: get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: Type ID in: path name: type_id required: true - type: string - produces: - - application/json + schema: + type: string responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/object.TypeResponse' description: The requested type - schema: - $ref: '#/definitions/object.TypeResponse' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Resource not found - schema: - $ref: '#/definitions/util.NotFoundError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Get type tags: - types /spaces/{space_id}/types/{type_id}/templates: get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: Type ID in: path name: type_id required: true - type: string - - default: 0 - description: The number of items to skip before starting to collect the result + schema: + type: string + - description: The number of items to skip before starting to collect the result set in: query name: offset - type: integer - - default: 100 - description: The number of items to return + schema: + default: 0 + type: integer + - description: The number of items to return in: query - maximum: 1000 name: limit - type: integer - produces: - - application/json + schema: + default: 100 + maximum: 1000 + type: integer responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-object_Template' description: List of templates - schema: - $ref: '#/definitions/pagination.PaginatedResponse-object_Template' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: List templates tags: - types /spaces/{space_id}/types/{type_id}/templates/{template_id}: get: - consumes: - - application/json parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: Type ID in: path name: type_id required: true - type: string + schema: + type: string - description: Template ID in: path name: template_id required: true - type: string - produces: - - application/json + schema: + type: string responses: "200": + content: + application/json: + schema: + $ref: '#/components/schemas/object.TemplateResponse' description: The requested template - schema: - $ref: '#/definitions/object.TemplateResponse' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Resource not found - schema: - $ref: '#/definitions/util.NotFoundError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' + security: + - bearerauth: [] summary: Get template tags: - types /v1/spaces/{space_id}/lists/{list_id}/objects: - delete: - consumes: - - application/json + get: parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: List ID in: path name: list_id required: true - type: string - - description: List of object IDs - in: body - name: objects - required: true schema: - items: - type: string - type: array - produces: - - application/json + type: string + - description: The number of items to skip before starting to collect the result + set + in: query + name: offset + schema: + default: 0 + type: integer + - description: The number of items to return + in: query + name: limit + schema: + type: integer responses: "200": - description: Objects removed successfully - schema: - type: string - "400": - description: Bad request - schema: - $ref: '#/definitions/util.ValidationError' + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-object_Object' + description: List of objects "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Not found - schema: - $ref: '#/definitions/util.NotFoundError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' - summary: Remove objects from list + security: + - bearerauth: [] + summary: Get objects in list tags: - lists - get: - consumes: - - application/json + post: parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: List ID in: path name: list_id required: true - type: string - - default: 0 - description: The number of items to skip before starting to collect the result - set - in: query - name: offset - type: integer - - description: The number of items to return - in: query - name: limit - type: integer - produces: - - application/json + schema: + type: string + requestBody: + content: + application/json: + schema: + items: + type: string + type: array + description: List of object IDs + required: true responses: "200": - description: List of objects - schema: - $ref: '#/definitions/pagination.PaginatedResponse-object_Object' + content: + application/json: + schema: + type: string + description: Objects added successfully + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ValidationError' + description: Bad request "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Not found - schema: - $ref: '#/definitions/util.NotFoundError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' - summary: Get objects in list + security: + - bearerauth: [] + summary: Add objects to list tags: - lists - post: - consumes: - - application/json + /v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}: + delete: parameters: - description: Space ID in: path name: space_id required: true - type: string + schema: + type: string - description: List ID in: path name: list_id required: true - type: string - - description: List of object IDs - in: body - name: objects + schema: + type: string + - description: Object ID + in: path + name: object_id required: true schema: - items: - type: string - type: array - produces: - - application/json + type: string responses: "200": - description: Objects added successfully - schema: - type: string + content: + application/json: + schema: + type: string + description: Objects removed successfully "400": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ValidationError' description: Bad request - schema: - $ref: '#/definitions/util.ValidationError' "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' description: Unauthorized - schema: - $ref: '#/definitions/util.UnauthorizedError' "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' description: Not found - schema: - $ref: '#/definitions/util.NotFoundError' "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' description: Internal server error - schema: - $ref: '#/definitions/util.ServerError' - summary: Add objects to list + security: + - bearerauth: [] + summary: Remove object from list tags: - lists -securityDefinitions: - ApiKeyAuth: - in: header - name: Authorization - type: apiKey -swagger: "2.0" +servers: +- url: localhost:31009/v1 diff --git a/core/api/internal/export/handler.go b/core/api/internal/export/handler.go index c2ae3a2f86..b0a2813a42 100644 --- a/core/api/internal/export/handler.go +++ b/core/api/internal/export/handler.go @@ -21,6 +21,7 @@ import ( // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/objects/{object_id}/export/{format} [post] func GetObjectExportHandler(s *ExportService) gin.HandlerFunc { return func(c *gin.Context) { diff --git a/core/api/internal/list/handler.go b/core/api/internal/list/handler.go index 0830390f53..c5c6871ae5 100644 --- a/core/api/internal/list/handler.go +++ b/core/api/internal/list/handler.go @@ -13,7 +13,6 @@ import ( // // @Summary Get objects in list // @Tags lists -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param list_id path string true "List ID" @@ -23,6 +22,7 @@ import ( // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Not found" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /v1/spaces/{space_id}/lists/{list_id}/objects [get] func GetObjectsInListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { @@ -60,6 +60,7 @@ func GetObjectsInListHandler(s *ListService) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Not found" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /v1/spaces/{space_id}/lists/{list_id}/objects [post] func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { @@ -88,34 +89,28 @@ func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { } } -// RemoveObjectsFromListHandler +// RemoveObjectFromListHandler // -// @Summary Remove objects from list +// @Summary Remove object from list // @Tags lists -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param list_id path string true "List ID" -// @Param objects body []string true "List of object IDs" +// @Param object_id path string true "Object ID" // @Success 200 {object} string "Objects removed successfully" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Not found" // @Failure 500 {object} util.ServerError "Internal server error" -// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [delete] -func RemoveObjectsFromListHandler(s *ListService) gin.HandlerFunc { +// @Security bearerauth +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects/{object_id} [delete] +func RemoveObjectFromListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") listId := c.Param("list_id") + objectId := c.Param("object_id") - objects := []string{} - if err := c.ShouldBindJSON(&objects); err != nil { - apiErr := util.CodeToAPIError(http.StatusBadRequest, err.Error()) - c.JSON(http.StatusBadRequest, apiErr) - return - } - - err := s.RemoveObjectsFromList(c, spaceId, listId, objects) + err := s.RemoveObjectFromList(c, spaceId, listId, objectId) code := util.MapErrorCode(err, util.ErrToCode(ErrFailedRemoveObjectsFromList, http.StatusInternalServerError), ) diff --git a/core/api/internal/list/service.go b/core/api/internal/list/service.go index 625e560506..75e6f8407c 100644 --- a/core/api/internal/list/service.go +++ b/core/api/internal/list/service.go @@ -20,7 +20,7 @@ var ( type Service interface { GetObjectsInList(ctx context.Context, spaceId string, listId string, offset, limit int) ([]object.Object, int, bool, error) AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIds []string) error - RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIds []string) error + RemoveObjectFromList(ctx context.Context, spaceId string, listId string, objectIds []string) error } type ListService struct { @@ -76,11 +76,11 @@ func (s *ListService) AddObjectsToList(ctx context.Context, spaceId string, list return nil } -// RemoveObjectsFromList removes objects from a list -func (s *ListService) RemoveObjectsFromList(ctx context.Context, spaceId string, listId string, objectIds []string) error { +// RemoveObjectFromList removes objects from a list +func (s *ListService) RemoveObjectFromList(ctx context.Context, spaceId string, listId string, objectId string) error { resp := s.mw.ObjectCollectionRemove(ctx, &pb.RpcObjectCollectionRemoveRequest{ ContextId: spaceId, - ObjectIds: objectIds, + ObjectIds: []string{objectId}, }) if resp.Error.Code != pb.RpcObjectCollectionRemoveResponseError_NULL { diff --git a/core/api/internal/object/handler.go b/core/api/internal/object/handler.go index 57c1e2e877..a8a0aa25d1 100644 --- a/core/api/internal/object/handler.go +++ b/core/api/internal/object/handler.go @@ -13,7 +13,6 @@ import ( // // @Summary List objects // @Tags objects -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) @@ -21,6 +20,7 @@ import ( // @Success 200 {object} pagination.PaginatedResponse[Object] "List of objects" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/objects [get] func GetObjectsHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { @@ -49,7 +49,6 @@ func GetObjectsHandler(s *ObjectService) gin.HandlerFunc { // // @Summary Get object // @Tags objects -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param object_id path string true "Object ID" @@ -57,6 +56,7 @@ func GetObjectsHandler(s *ObjectService) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Resource not found" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/objects/{object_id} [get] func GetObjectHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { @@ -83,7 +83,6 @@ func GetObjectHandler(s *ObjectService) gin.HandlerFunc { // // @Summary Delete object // @Tags objects -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param object_id path string true "Object ID" @@ -93,6 +92,7 @@ func GetObjectHandler(s *ObjectService) gin.HandlerFunc { // @Failure 404 {object} util.NotFoundError "Resource not found" // @Failure 423 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/objects/{object_id} [delete] func DeleteObjectHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { @@ -129,6 +129,7 @@ func DeleteObjectHandler(s *ObjectService) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 423 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/objects [post] func CreateObjectHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { @@ -165,7 +166,6 @@ func CreateObjectHandler(s *ObjectService) gin.HandlerFunc { // // @Summary List types // @Tags types -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) @@ -173,6 +173,7 @@ func CreateObjectHandler(s *ObjectService) gin.HandlerFunc { // @Success 200 {object} pagination.PaginatedResponse[Type] "List of types" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/types [get] func GetTypesHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { @@ -199,7 +200,6 @@ func GetTypesHandler(s *ObjectService) gin.HandlerFunc { // // @Summary Get type // @Tags types -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param type_id path string true "Type ID" @@ -207,6 +207,7 @@ func GetTypesHandler(s *ObjectService) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Resource not found" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/types/{type_id} [get] func GetTypeHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { @@ -233,7 +234,6 @@ func GetTypeHandler(s *ObjectService) gin.HandlerFunc { // // @Summary List templates // @Tags types -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param type_id path string true "Type ID" @@ -242,6 +242,7 @@ func GetTypeHandler(s *ObjectService) gin.HandlerFunc { // @Success 200 {object} pagination.PaginatedResponse[Template] "List of templates" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/types/{type_id}/templates [get] func GetTemplatesHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { @@ -272,7 +273,6 @@ func GetTemplatesHandler(s *ObjectService) gin.HandlerFunc { // // @Summary Get template // @Tags types -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param type_id path string true "Type ID" @@ -281,6 +281,7 @@ func GetTemplatesHandler(s *ObjectService) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Resource not found" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/types/{type_id}/templates/{template_id} [get] func GetTemplateHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { diff --git a/core/api/internal/search/handler.go b/core/api/internal/search/handler.go index e3ffe62ed8..57bbe33182 100644 --- a/core/api/internal/search/handler.go +++ b/core/api/internal/search/handler.go @@ -21,6 +21,7 @@ import ( // @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /search [post] func GlobalSearchHandler(s *SearchService) gin.HandlerFunc { return func(c *gin.Context) { @@ -62,6 +63,7 @@ func GlobalSearchHandler(s *SearchService) gin.HandlerFunc { // @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/search [post] func SearchHandler(s *SearchService) gin.HandlerFunc { return func(c *gin.Context) { diff --git a/core/api/internal/space/handler.go b/core/api/internal/space/handler.go index 5dbbd2cd83..8c67c671b5 100644 --- a/core/api/internal/space/handler.go +++ b/core/api/internal/space/handler.go @@ -13,13 +13,13 @@ import ( // // @Summary List spaces // @Tags spaces -// @Accept json // @Produce json // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Success 200 {object} pagination.PaginatedResponse[Space] "List of spaces" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces [get] func GetSpacesHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { @@ -46,13 +46,13 @@ func GetSpacesHandler(s *SpaceService) gin.HandlerFunc { // // @Summary Get space // @Tags spaces -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Success 200 {object} SpaceResponse "Space" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Space not found" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id} [get] func GetSpaceHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { @@ -86,6 +86,7 @@ func GetSpaceHandler(s *SpaceService) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 423 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces [post] func CreateSpaceHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { @@ -115,7 +116,6 @@ func CreateSpaceHandler(s *SpaceService) gin.HandlerFunc { // // @Summary List members // @Tags spaces -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) @@ -123,6 +123,7 @@ func CreateSpaceHandler(s *SpaceService) gin.HandlerFunc { // @Success 200 {object} pagination.PaginatedResponse[Member] "List of members" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/members [get] func GetMembersHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { @@ -149,7 +150,6 @@ func GetMembersHandler(s *SpaceService) gin.HandlerFunc { // // @Summary Get member // @Tags spaces -// @Accept json // @Produce json // @Param space_id path string true "Space ID" // @Param member_id path string true "Member ID" @@ -157,6 +157,7 @@ func GetMembersHandler(s *SpaceService) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Member not found" // @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth // @Router /spaces/{space_id}/members/{member_id} [get] func GetMemberHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { diff --git a/core/api/server/router.go b/core/api/server/router.go index 6bc0174119..f3397da1c0 100644 --- a/core/api/server/router.go +++ b/core/api/server/router.go @@ -70,7 +70,7 @@ func (s *Server) NewRouter(accountService account.Service, mw service.ClientComm // List v1.GET("/spaces/:space_id/lists/:list_id/objects", list.GetObjectsInListHandler(s.listService)) v1.POST("/spaces/:space_id/lists/:list_id/objects", list.AddObjectsToListHandler(s.listService)) - v1.DELETE("/spaces/:space_id/lists/:list_id/objects", list.RemoveObjectsFromListHandler(s.listService)) + v1.DELETE("/spaces/:space_id/lists/:list_id/objects/:object_id", s.rateLimit(maxWriteRequestsPerSecond), list.RemoveObjectFromListHandler(s.listService)) // Object v1.GET("/spaces/:space_id/objects", object.GetObjectsHandler(s.objectService)) diff --git a/core/api/service.go b/core/api/service.go index d6cb17d475..4917f51d82 100644 --- a/core/api/service.go +++ b/core/api/service.go @@ -49,22 +49,20 @@ func (s *apiService) Name() (name string) { // Init initializes the API service. // -// @title Anytype API -// @version 1.0 -// @description This API allows interaction with Anytype resources such as spaces, objects and types. -// @termsOfService https://anytype.io/terms_of_use -// @contact.name Anytype Support -// @contact.url https://anytype.io/contact -// @contact.email support@anytype.io -// @license.name Any Source Available License 1.0 -// @license.url https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md -// @host localhost:31009 -// @BasePath /v1 -// @securityDefinitions.apikey ApiKeyAuth -// @in header -// @name Authorization -// @externalDocs.description OpenAPI -// @externalDocs.url https://swagger.io/resources/open-api/ +// @title Anytype API +// @version 1.0 +// @description This API allows interaction with Anytype resources such as spaces, objects and types. +// @termsOfService https://anytype.io/terms_of_use +// @contact.name Anytype Support +// @contact.url https://anytype.io/contact +// @contact.email support@anytype.io +// @license.name Any Source Available License 1.0 +// @license.url https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md +// @host localhost:31009 +// @BasePath /v1 +// @securitydefinitions.bearerauth BearerAuth +// @externalDocs.description OpenAPI +// @externalDocs.url https://swagger.io/resources/open-api/ func (s *apiService) Init(a *app.App) (err error) { s.listenAddr = a.MustComponent(config.CName).(*config.Config).JsonApiListenAddr s.accountService = a.MustComponent(account.CName).(account.Service) diff --git a/go.mod b/go.mod index 829142b213..bfba1e94a5 100644 --- a/go.mod +++ b/go.mod @@ -169,10 +169,10 @@ require ( github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.6 // indirect - github.com/go-openapi/spec v0.20.4 // indirect - github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/spec v0.20.9 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/go-pkgz/expirable-cache/v3 v3.0.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -220,7 +220,7 @@ require ( github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-libp2p v0.38.2 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/mailru/easyjson v0.7.6 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/miekg/dns v1.1.62 // indirect @@ -265,6 +265,8 @@ require ( github.com/spf13/viper v1.15.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.2 // indirect + github.com/sv-tools/openapi v0.2.1 // indirect + github.com/swaggo/swag/v2 v2.0.0-rc4 // indirect github.com/tetratelabs/wazero v1.8.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect diff --git a/go.sum b/go.sum index 99d0be11d0..dbfd5264e2 100644 --- a/go.sum +++ b/go.sum @@ -353,13 +353,22 @@ github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-pkgz/expirable-cache/v3 v3.0.0 h1:u3/gcu3sabLYiTCevoRKv+WzjIn5oo7P8XtiXBeRDLw= github.com/go-pkgz/expirable-cache/v3 v3.0.0/go.mod h1:2OQiDyEGQalYecLWmXprm3maPXeVb5/6/X7yRPYTzec= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -684,6 +693,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -728,6 +738,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matishsiao/goInfo v0.0.0-20240924010139-10388a85396f h1:XDrsC/9hdgiU9ecceSmYsS2E3fBtFiYc34dAMFgegnM= github.com/matishsiao/goInfo v0.0.0-20240924010139-10388a85396f/go.mod h1:aEt7p9Rvh67BYApmZwNDPpgircTO2kgdmDUoF/1QmwA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -1056,12 +1068,16 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/sv-tools/openapi v0.2.1 h1:ES1tMQMJFGibWndMagvdoo34T1Vllxr1Nlm5wz6b1aA= +github.com/sv-tools/openapi v0.2.1/go.mod h1:k5VuZamTw1HuiS9p2Wl5YIDWzYnHG6/FgPOSFXLAhGg= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= +github.com/swaggo/swag/v2 v2.0.0-rc4 h1:SZ8cK68gcV6cslwrJMIOqPkJELRwq4gmjvk77MrvHvY= +github.com/swaggo/swag/v2 v2.0.0-rc4/go.mod h1:Ow7Y8gF16BTCDn8YxZbyKn8FkMLRUHekv1kROJZpbvE= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550= github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= From 1c87b864a51baa828c0f993320d30f334efec40b Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sun, 16 Feb 2025 13:56:17 +0100 Subject: [PATCH 22/31] GO-4459: Add http prefix to host --- core/api/docs/docs.go | 2 +- core/api/docs/swagger.json | 2 +- core/api/docs/swagger.yaml | 2 +- core/api/service.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 2faeb5526a..01dd8e76e0 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -12,7 +12,7 @@ const docTemplate = `{ "paths": {"/auth/display_code":{"post":{"parameters":[{"description":"App name requesting the challenge","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.DisplayCodeResponse"}}},"description":"Challenge ID"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["auth"]}},"/auth/token":{"post":{"parameters":[{"description":"Challenge ID","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.TokenResponse"}}},"description":"Authentication token"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Retrieve token","tags":["auth"]}},"/search":{"post":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["search"]}},"/spaces":{"get":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Space"}}},"description":"List of spaces"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["spaces"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.CreateSpaceRequest"}}},"description":"Space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space created successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["spaces"]}},"/spaces/{space_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["spaces"]}},"/spaces/{space_id}/members":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Member"}}},"description":"List of members"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["spaces"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.MemberResponse"}}},"description":"Member"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["spaces"]}},"/spaces/{space_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["objects"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.CreateObjectRequest"}}},"description":"Object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["objects"]},"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The requested object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}/export/{format}":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"Export format","in":"path","name":"format","required":true,"schema":{"enum":["markdown","protobuf"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/export.ObjectExportResponse"}}},"description":"Object exported successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Export object","tags":["export"]}},"/spaces/{space_id}/search":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["search"]}},"/spaces/{space_id}/types":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Type"}}},"description":"List of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["types"]}},"/spaces/{space_id}/types/{type_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Template"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"Template ID","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["types"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["lists"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"List of object IDs","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["lists"]}}}, "openapi": "3.1.0", "servers": [ - {"url":"localhost:31009/v1"} + {"url":"http://localhost:31009/v1"} ] }` diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index c79693d6bf..3247b1acfb 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -5,6 +5,6 @@ "paths": {"/auth/display_code":{"post":{"parameters":[{"description":"App name requesting the challenge","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.DisplayCodeResponse"}}},"description":"Challenge ID"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["auth"]}},"/auth/token":{"post":{"parameters":[{"description":"Challenge ID","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.TokenResponse"}}},"description":"Authentication token"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Retrieve token","tags":["auth"]}},"/search":{"post":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["search"]}},"/spaces":{"get":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Space"}}},"description":"List of spaces"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["spaces"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.CreateSpaceRequest"}}},"description":"Space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space created successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["spaces"]}},"/spaces/{space_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["spaces"]}},"/spaces/{space_id}/members":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Member"}}},"description":"List of members"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["spaces"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.MemberResponse"}}},"description":"Member"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["spaces"]}},"/spaces/{space_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["objects"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.CreateObjectRequest"}}},"description":"Object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["objects"]},"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The requested object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}/export/{format}":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"Export format","in":"path","name":"format","required":true,"schema":{"enum":["markdown","protobuf"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/export.ObjectExportResponse"}}},"description":"Object exported successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Export object","tags":["export"]}},"/spaces/{space_id}/search":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["search"]}},"/spaces/{space_id}/types":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Type"}}},"description":"List of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["types"]}},"/spaces/{space_id}/types/{type_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Template"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"Template ID","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["types"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["lists"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"List of object IDs","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["lists"]}}}, "openapi": "3.1.0", "servers": [ - {"url":"localhost:31009/v1"} + {"url":"http://localhost:31009/v1"} ] } \ No newline at end of file diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index deb31aec21..2c3ff7a8e8 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -1660,4 +1660,4 @@ paths: tags: - lists servers: -- url: localhost:31009/v1 +- url: http://localhost:31009/v1 diff --git a/core/api/service.go b/core/api/service.go index 4917f51d82..4d98e334d7 100644 --- a/core/api/service.go +++ b/core/api/service.go @@ -58,7 +58,7 @@ func (s *apiService) Name() (name string) { // @contact.email support@anytype.io // @license.name Any Source Available License 1.0 // @license.url https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md -// @host localhost:31009 +// @host http://localhost:31009 // @BasePath /v1 // @securitydefinitions.bearerauth BearerAuth // @externalDocs.description OpenAPI From 5b5da7d7071f152e2844cf03b82b11304aceb0a6 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sun, 16 Feb 2025 18:21:41 +0100 Subject: [PATCH 23/31] GO-4459: Add `swagger` Make target to generate and format swagger docs --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index cffe394874..2927a6e109 100644 --- a/Makefile +++ b/Makefile @@ -338,6 +338,12 @@ else @golangci-lint run -v ./... --new-from-rev=origin/main --timeout 15m --fix endif +swagger: + @echo 'Generating swagger docs...' + @swag init --v3.1 -q -d core/api -g service.go -o core/api/docs + @echo 'Formatting swagger docs...' + @swag fmt -d core/api + ### Tantivy Section REPO := anyproto/tantivy-go From fd66a264f83c5c56194897b542fd927d57d752aa Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Sun, 16 Feb 2025 19:14:18 +0100 Subject: [PATCH 24/31] GO-4459: Add resolveTag method to handle tag/status option as string instead of list bug --- core/api/internal/object/service.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index 0079b90952..ad86898c79 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -560,6 +560,12 @@ func (s *ObjectService) convertValue(value *types.Value, format string, key stri } return member } + + // TODO: investigate how this is possible? select option not list and not returned in further details + if format == "select" || format == "multi_select" { + return s.resolveTag(details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), kind.StringValue) + } + return kind.StringValue case *types.Value_BoolValue: return kind.BoolValue @@ -604,6 +610,28 @@ func (s *ObjectService) getRelationFormatMap(relationLinks []*model.RelationLink return relationFormatMap } +// TODO: remove once bug of select option not being returned in details is fixed +func (s *ObjectService) resolveTag(spaceId, tagId string) Tag { + if tagId == "" { + return Tag{} + } + + resp := s.mw.ObjectShow(context.Background(), &pb.RpcObjectShowRequest{ + SpaceId: spaceId, + ObjectId: tagId, + }) + + if resp.Error.Code != pb.RpcObjectShowResponseError_NULL { + return Tag{} + } + + return Tag{ + Id: tagId, + Name: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue(), + Color: resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyRelationOptionColor.String()].GetStringValue(), + } +} + // getTags returns the list of tags from the ObjectShowResponse func (s *ObjectService) getTags(key string, details []*model.ObjectViewDetailsSet) []Tag { tags := []Tag{} From cdf1787bf1e341bb8941db4f6e54e4c8554e266c Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Mon, 17 Feb 2025 13:54:41 +0100 Subject: [PATCH 25/31] GO-4459: Add layout align to excluded relations --- core/api/internal/object/service.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index ad86898c79..420e2824df 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -497,6 +497,7 @@ func (s *ObjectService) getDetails(resp *pb.RpcObjectShowResponse) []Detail { bundle.RelationKeyLinks.String(): true, bundle.RelationKeyBacklinks.String(): true, bundle.RelationKeySourceObject.String(): true, + bundle.RelationKeyLayoutAlign.String(): true, } var details []Detail From ff88402e626dee7aed230b9673794d0e04b29fe8 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Mon, 17 Feb 2025 15:50:38 +0100 Subject: [PATCH 26/31] GO-4459: Add missing filter condition for relation name resolution --- core/api/internal/object/service.go | 6 +++--- core/api/util/util.go | 17 ++++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index 420e2824df..3565976a7e 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -526,11 +526,11 @@ func (s *ObjectService) getDetails(resp *pb.RpcObjectShowResponse) []Detail { func (s *ObjectService) getRelation(key string, resp *pb.RpcObjectShowResponse) (id string, name string) { relation, err := bundle.GetRelation(domain.RelationKey(key)) if err != nil { - relation, err = util.ResolveRelationKeyToRelationName(s.mw, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), key) + name, err = util.ResolveRelationKeyToRelationName(s.mw, resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), key) if err != nil { - return strcase.ToSnake(key), key + return key, key } - return key, relation.Name + return key, name } // special cases of relation keys and names diff --git a/core/api/util/util.go b/core/api/util/util.go index 25eacf1d25..568a5c3bc5 100644 --- a/core/api/util/util.go +++ b/core/api/util/util.go @@ -61,7 +61,7 @@ func ResolveUniqueKeyToTypeId(mw service.ClientCommandsServer, spaceId string, u return resp.Records[0].Fields[bundle.RelationKeyId.String()].GetStringValue(), nil } -func ResolveRelationKeyToRelationName(mw service.ClientCommandsServer, spaceId string, relationKey string) (relation *model.Relation, err error) { +func ResolveRelationKeyToRelationName(mw service.ClientCommandsServer, spaceId string, relationKey string) (relation string, err error) { resp := mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -70,19 +70,22 @@ func ResolveRelationKeyToRelationName(mw service.ClientCommandsServer, spaceId s Condition: model.BlockContentDataviewFilter_Equal, Value: pbtypes.String(relationKey), }, + { + RelationKey: bundle.RelationKeyLayout.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.Int64(int64(model.ObjectType_relation)), + }, }, - Keys: []string{bundle.RelationKeyId.String(), bundle.RelationKeyName.String()}, + Keys: []string{bundle.RelationKeyId.String(), bundle.RelationKeyName.String(), bundle.RelationKeyLayout.String()}, }) if resp.Error.Code != pb.RpcObjectSearchResponseError_NULL { - return &model.Relation{}, ErrFailedSearchType + return "", ErrFailedSearchType } if len(resp.Records) == 0 { - return &model.Relation{}, ErrorTypeNotFound + return "", ErrorTypeNotFound } - return &model.Relation{ - Name: resp.Records[0].Fields[bundle.RelationKeyName.String()].GetStringValue(), - }, nil + return resp.Records[0].Fields[bundle.RelationKeyName.String()].GetStringValue(), nil } From 394922dae773ae221137d7283a2c0dd288372d7e Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Mon, 17 Feb 2025 17:05:45 +0100 Subject: [PATCH 27/31] GO-4459: Fix tests for space and object --- core/api/internal/object/service_test.go | 107 +++++++++++++++++++++-- core/api/internal/search/service_test.go | 100 +++++++++++++++++++++ 2 files changed, 201 insertions(+), 6 deletions(-) diff --git a/core/api/internal/object/service_test.go b/core/api/internal/object/service_test.go index 447f2f6913..1c78386322 100644 --- a/core/api/internal/object/service_test.go +++ b/core/api/internal/object/service_test.go @@ -65,6 +65,29 @@ func TestObjectService_ListObjects(t *testing.T) { ctx := context.Background() fx := newFixture(t) + // Mock template type resolution + fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ + SpaceId: mockedSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyUniqueKey.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.String("ot-template"), + }, + }, + Keys: []string{bundle.RelationKeyId.String()}, + }).Return(&pb.RpcObjectSearchResponse{ + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Records: []*types.Struct{ + { + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), + }, + }, + }, + }).Once() + + // Mock object search fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -82,6 +105,18 @@ func TestObjectService_ListObjects(t *testing.T) { int(model.ObjectType_participant), }...), }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyType.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.String(mockedTypeId), + }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyIsHidden.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.Bool(true), + }, }, Sorts: []*model.BlockContentDataviewSort{{ RelationKey: bundle.RelationKeyLastModifiedDate.String(), @@ -257,14 +292,74 @@ func TestObjectService_ListObjects(t *testing.T) { ctx := context.Background() fx := newFixture(t) - fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything). - Return(&pb.RpcObjectSearchResponse{ - Records: []*types.Struct{}, - Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, - }).Once() + // Mock template type resolution + fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ + SpaceId: mockedSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyUniqueKey.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.String("ot-template"), + }, + }, + Keys: []string{bundle.RelationKeyId.String()}, + }).Return(&pb.RpcObjectSearchResponse{ + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Records: []*types.Struct{ + { + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedTypeId), + }, + }, + }, + }).Once() + + // Mock object search + fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ + SpaceId: mockedSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyLayout.String(), + Condition: model.BlockContentDataviewFilter_In, + Value: pbtypes.IntList([]int{ + int(model.ObjectType_basic), + int(model.ObjectType_profile), + int(model.ObjectType_todo), + int(model.ObjectType_note), + int(model.ObjectType_bookmark), + int(model.ObjectType_set), + int(model.ObjectType_collection), + int(model.ObjectType_participant), + }...), + }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyType.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.String(mockedTypeId), + }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyIsHidden.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.Bool(true), + }, + }, + Sorts: []*model.BlockContentDataviewSort{{ + RelationKey: bundle.RelationKeyLastModifiedDate.String(), + Type: model.BlockContentDataviewSort_Desc, + Format: model.RelationFormat_longtext, + IncludeTime: true, + EmptyPlacement: model.BlockContentDataviewSort_NotSpecified, + }}, + Keys: []string{bundle.RelationKeyId.String(), bundle.RelationKeyName.String()}, + }).Return(&pb.RpcObjectSearchResponse{ + Records: []*types.Struct{}, + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + }).Once() // when - objects, total, hasMore, err := fx.ListObjects(ctx, "empty-space", offset, limit) + objects, total, hasMore, err := fx.ListObjects(ctx, mockedSpaceId, offset, limit) // then require.NoError(t, err) diff --git a/core/api/internal/search/service_test.go b/core/api/internal/search/service_test.go index c6d1e023ad..f7e3eb288a 100644 --- a/core/api/internal/search/service_test.go +++ b/core/api/internal/search/service_test.go @@ -120,6 +120,28 @@ func TestSearchService_GlobalSearch(t *testing.T) { Error: &pb.RpcWorkspaceOpenResponseError{Code: pb.RpcWorkspaceOpenResponseError_NULL}, }).Once() + // Mock template type resolution + fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ + SpaceId: mockedSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyUniqueKey.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.String("ot-template"), + }, + }, + Keys: []string{bundle.RelationKeyId.String()}, + }).Return(&pb.RpcObjectSearchResponse{ + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Records: []*types.Struct{ + { + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedType), + }, + }, + }, + }).Once() + // Mock objects in space fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -148,6 +170,12 @@ func TestSearchService_GlobalSearch(t *testing.T) { Condition: model.BlockContentDataviewFilter_NotEqual, Value: pbtypes.Bool(true), }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyType.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.String(mockedType), + }, { Operator: model.BlockContentDataviewFilter_Or, NestedFilters: []*model.BlockContentDataviewFilter{ @@ -406,6 +434,28 @@ func TestSearchService_Search(t *testing.T) { ctx := context.Background() fx := newFixture(t) + // Mock template type resolution + fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ + SpaceId: mockedSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyUniqueKey.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.String("ot-template"), + }, + }, + Keys: []string{bundle.RelationKeyId.String()}, + }).Return(&pb.RpcObjectSearchResponse{ + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Records: []*types.Struct{ + { + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedType), + }, + }, + }, + }).Once() + // Mock objects in space fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -434,6 +484,12 @@ func TestSearchService_Search(t *testing.T) { Condition: model.BlockContentDataviewFilter_NotEqual, Value: pbtypes.Bool(true), }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyType.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.String(mockedType), + }, { Operator: model.BlockContentDataviewFilter_Or, NestedFilters: []*model.BlockContentDataviewFilter{ @@ -530,6 +586,28 @@ func TestSearchService_Search(t *testing.T) { ctx := context.Background() fx := newFixture(t) + // Mock template type resolution + fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ + SpaceId: mockedSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyUniqueKey.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.String("ot-template"), + }, + }, + Keys: []string{bundle.RelationKeyId.String()}, + }).Return(&pb.RpcObjectSearchResponse{ + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Records: []*types.Struct{ + { + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedType), + }, + }, + }, + }).Once() + fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything).Return(&pb.RpcObjectSearchResponse{ Records: []*types.Struct{}, Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, @@ -550,6 +628,28 @@ func TestSearchService_Search(t *testing.T) { ctx := context.Background() fx := newFixture(t) + // Mock template type resolution + fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ + SpaceId: mockedSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyUniqueKey.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.String("ot-template"), + }, + }, + Keys: []string{bundle.RelationKeyId.String()}, + }).Return(&pb.RpcObjectSearchResponse{ + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + Records: []*types.Struct{ + { + Fields: map[string]*types.Value{ + bundle.RelationKeyId.String(): pbtypes.String(mockedType), + }, + }, + }, + }).Once() + fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything).Return(&pb.RpcObjectSearchResponse{ Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_UNKNOWN_ERROR}, }).Once() From 79e72a51fe1bfb9c98b2a86a888a6f8cbd66bc87 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Mon, 17 Feb 2025 17:06:50 +0100 Subject: [PATCH 28/31] GO-4459: Remove templates from search and object list results --- core/api/internal/object/service.go | 19 +++++++++++++++++++ core/api/internal/search/service.go | 27 +++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index 3565976a7e..acc74b2a5b 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -64,10 +64,13 @@ func NewService(mw service.ClientCommandsServer, spaceService *space.SpaceServic // ListObjects retrieves a paginated list of objects in a specific space. func (s *ObjectService) ListObjects(ctx context.Context, spaceId string, offset int, limit int) (objects []Object, total int, hasMore bool, err error) { + typeId, err := util.ResolveUniqueKeyToTypeId(s.mw, spaceId, "ot-template") + resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { + Operator: model.BlockContentDataviewFilter_No, RelationKey: bundle.RelationKeyLayout.String(), Condition: model.BlockContentDataviewFilter_In, Value: pbtypes.IntList([]int{ @@ -81,6 +84,18 @@ func (s *ObjectService) ListObjects(ctx context.Context, spaceId string, offset int(model.ObjectType_participant), }...), }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyType.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.String(typeId), + }, + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyIsHidden.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.Bool(true), + }, }, Sorts: []*model.BlockContentDataviewSort{{ RelationKey: bundle.RelationKeyLastModifiedDate.String(), @@ -268,11 +283,13 @@ func (s *ObjectService) ListTypes(ctx context.Context, spaceId string, offset in SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { + Operator: model.BlockContentDataviewFilter_No, RelationKey: bundle.RelationKeyLayout.String(), Condition: model.BlockContentDataviewFilter_Equal, Value: pbtypes.Int64(int64(model.ObjectType_objectType)), }, { + Operator: model.BlockContentDataviewFilter_No, RelationKey: bundle.RelationKeyIsHidden.String(), Condition: model.BlockContentDataviewFilter_NotEqual, Value: pbtypes.Bool(true), @@ -340,6 +357,7 @@ func (s *ObjectService) ListTemplates(ctx context.Context, spaceId string, typeI SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { + Operator: model.BlockContentDataviewFilter_No, RelationKey: bundle.RelationKeyUniqueKey.String(), Condition: model.BlockContentDataviewFilter_Equal, Value: pbtypes.String("ot-template"), @@ -362,6 +380,7 @@ func (s *ObjectService) ListTemplates(ctx context.Context, spaceId string, typeI SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { + Operator: model.BlockContentDataviewFilter_No, RelationKey: bundle.RelationKeyType.String(), Condition: model.BlockContentDataviewFilter_Equal, Value: pbtypes.String(templateTypeId), diff --git a/core/api/internal/search/service.go b/core/api/internal/search/service.go index ecd2408718..c325560e3a 100644 --- a/core/api/internal/search/service.go +++ b/core/api/internal/search/service.go @@ -52,9 +52,10 @@ func (s *SearchService) GlobalSearch(ctx context.Context, request SearchRequest, allResponses := make([]*pb.RpcObjectSearchResponse, 0, len(spaces)) for _, space := range spaces { - // Resolve object type IDs per space, as they are unique per space + // Resolve template type and object type IDs per space, as they are unique per space + templateFilter := s.prepareTemplateFilter(space.Id) typeFilters := s.prepareObjectTypeFilters(space.Id, request.Types) - filters := s.combineFilters(model.BlockContentDataviewFilter_And, baseFilters, queryFilters, typeFilters) + filters := s.combineFilters(model.BlockContentDataviewFilter_And, baseFilters, templateFilter, queryFilters, typeFilters) objResp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: space.Id, @@ -113,9 +114,10 @@ func (s *SearchService) GlobalSearch(ctx context.Context, request SearchRequest, // Search retrieves a paginated list of objects from a specific space that match the search parameters. func (s *SearchService) Search(ctx context.Context, spaceId string, request SearchRequest, offset int, limit int) (objects []object.Object, total int, hasMore bool, err error) { baseFilters := s.prepareBaseFilters() + templateFilter := s.prepareTemplateFilter(spaceId) queryFilters := s.prepareQueryFilter(request.Query) typeFilters := s.prepareObjectTypeFilters(spaceId, request.Types) - filters := s.combineFilters(model.BlockContentDataviewFilter_And, baseFilters, queryFilters, typeFilters) + filters := s.combineFilters(model.BlockContentDataviewFilter_And, baseFilters, templateFilter, queryFilters, typeFilters) sorts := s.prepareSorts(request.Sort) dateToSortAfter := sorts[0].RelationKey @@ -194,6 +196,23 @@ func (s *SearchService) prepareBaseFilters() []*model.BlockContentDataviewFilter } } +// prepareTemplateFilter returns a filter that excludes templates from the search results. +func (s *SearchService) prepareTemplateFilter(spaceId string) []*model.BlockContentDataviewFilter { + typeId, err := util.ResolveUniqueKeyToTypeId(s.mw, spaceId, "ot-template") + if err != nil { + return nil + } + + return []*model.BlockContentDataviewFilter{ + { + Operator: model.BlockContentDataviewFilter_No, + RelationKey: bundle.RelationKeyType.String(), + Condition: model.BlockContentDataviewFilter_NotEqual, + Value: pbtypes.String(typeId), + }, + } +} + // prepareQueryFilter combines object name and snippet filters with an OR condition. func (s *SearchService) prepareQueryFilter(searchQuery string) []*model.BlockContentDataviewFilter { if searchQuery == "" { @@ -243,7 +262,7 @@ func (s *SearchService) prepareObjectTypeFilters(spaceId string, objectTypes []s nestedFilters = append(nestedFilters, &model.BlockContentDataviewFilter{ Operator: model.BlockContentDataviewFilter_No, RelationKey: bundle.RelationKeyType.String(), - Condition: model.BlockContentDataviewFilter_Equal, + Condition: model.BlockContentDataviewFilter_NotEqual, Value: pbtypes.String(typeId), }) } From fefb3b8b7d17d6d05c2007f2639802670f9cd744 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Mon, 17 Feb 2025 17:24:51 +0100 Subject: [PATCH 29/31] GO-4459: Fix tags in search test --- core/api/internal/object/service.go | 17 +++++----- core/api/internal/search/service_test.go | 40 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/core/api/internal/object/service.go b/core/api/internal/object/service.go index acc74b2a5b..9fdc624405 100644 --- a/core/api/internal/object/service.go +++ b/core/api/internal/object/service.go @@ -521,19 +521,20 @@ func (s *ObjectService) getDetails(resp *pb.RpcObjectShowResponse) []Detail { var details []Detail for _, r := range linkedRelations { - if _, isExcluded := excludeRelations[r.Key]; isExcluded { + key := r.Key + if _, isExcluded := excludeRelations[key]; isExcluded { continue } - if val, ok := primaryDetailFields[r.Key]; ok { - id, name := s.getRelation(r.Key, resp) - format := relationFormatMap[r.Key] + if val, ok := primaryDetailFields[key]; ok { + id, name := s.getRelation(key, resp) + format := relationFormatMap[key] details = append(details, Detail{ Id: id, Details: map[string]interface{}{ "name": name, "type": format, - format: s.convertValue(val, format, r.Key, resp.ObjectView.Details), + format: s.convertValue(key, val, format, resp.ObjectView.Details), }, }) } @@ -563,7 +564,7 @@ func (s *ObjectService) getRelation(key string, resp *pb.RpcObjectShowResponse) } // convertValue converts a protobuf types.Value into a native Go value. -func (s *ObjectService) convertValue(value *types.Value, format string, key string, details []*model.ObjectViewDetailsSet) interface{} { +func (s *ObjectService) convertValue(key string, value *types.Value, format string, details []*model.ObjectViewDetailsSet) interface{} { switch kind := value.Kind.(type) { case *types.Value_NullValue: return nil @@ -592,13 +593,13 @@ func (s *ObjectService) convertValue(value *types.Value, format string, key stri case *types.Value_StructValue: m := make(map[string]interface{}) for k, v := range kind.StructValue.Fields { - m[k] = s.convertValue(v, format, key, details) + m[k] = s.convertValue(key, v, format, details) } return m case *types.Value_ListValue: var list []interface{} for _, v := range kind.ListValue.Values { - list = append(list, s.convertValue(v, format, key, details)) + list = append(list, s.convertValue(key, v, format, details)) } if format == "select" || format == "multi_select" { diff --git a/core/api/internal/search/service_test.go b/core/api/internal/search/service_test.go index f7e3eb288a..2e0eac3ee8 100644 --- a/core/api/internal/search/service_test.go +++ b/core/api/internal/search/service_test.go @@ -375,6 +375,46 @@ func TestSearchService_GlobalSearch(t *testing.T) { Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Twice() + // Mock tag-1 open + fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedTagId1, + }).Return(&pb.RpcObjectShowResponse{ + Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, + ObjectView: &model.ObjectView{ + Details: []*model.ObjectViewDetailsSet{ + { + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyName.String(): pbtypes.String(mockedTagValue1), + bundle.RelationKeyRelationOptionColor.String(): pbtypes.String(mockedTagColor1), + }, + }, + }, + }, + }, + }, nil).Once() + + // Mock tag-2 open + fx.mwMock.On("ObjectShow", mock.Anything, &pb.RpcObjectShowRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedTagId2, + }).Return(&pb.RpcObjectShowResponse{ + Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, + ObjectView: &model.ObjectView{ + Details: []*model.ObjectViewDetailsSet{ + { + Details: &types.Struct{ + Fields: map[string]*types.Value{ + bundle.RelationKeyName.String(): pbtypes.String(mockedTagValue2), + bundle.RelationKeyRelationOptionColor.String(): pbtypes.String(mockedTagColor2), + }, + }, + }, + }, + }, + }, nil).Once() + // when objects, total, hasMore, err := fx.GlobalSearch(ctx, SearchRequest{Query: mockedSearchTerm, Types: []string{}, Sort: SortOptions{Direction: "desc", Timestamp: "last_modified_date"}}, offset, limit) From 4df66f60ce3095ceab99dc3931b3855053e61521 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Thu, 20 Feb 2025 17:41:27 +0100 Subject: [PATCH 30/31] GO-4459: Add endpoint descriptions --- core/api/docs/docs.go | 2 +- core/api/docs/swagger.json | 2 +- core/api/docs/swagger.yaml | 115 ++++++++++++++++ core/api/internal/auth/handler.go | 40 +++--- core/api/internal/export/handler.go | 27 ++-- core/api/internal/list/handler.go | 83 ++++++------ core/api/internal/object/handler.go | 196 +++++++++++++++------------- core/api/internal/search/handler.go | 52 ++++---- core/api/internal/space/handler.go | 113 ++++++++-------- 9 files changed, 383 insertions(+), 247 deletions(-) diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index 01dd8e76e0..5698574b87 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -9,7 +9,7 @@ const docTemplate = `{ "components": {"schemas":{"auth.DisplayCodeResponse":{"properties":{"challenge_id":{"description":"The challenge id associated with the displayed code and needed to solve the challenge for token","example":"67647f5ecda913e9a2e11b26","type":"string"}},"type":"object"},"auth.TokenResponse":{"properties":{"app_key":{"description":"The permanent app key","example":"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=","type":"string"},"session_token":{"description":"The ephemeral session token","example":"eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII","type":"string"}},"type":"object"},"export.ObjectExportResponse":{"properties":{"path":{"description":"The path the object was exported to","example":"/path/to/export","type":"string"}},"type":"object"},"object.Block":{"properties":{"align":{"description":"The alignment of the block","enum":["AlignLeft","AlignCenter","AlignRight","AlignJustify"],"example":"AlignLeft","type":"string"},"background_color":{"description":"The background color of the block","example":"red","type":"string"},"children_ids":{"description":"The ids of the block's children","example":["['6797ce8ecda913cde14b02dc']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"file":{"$ref":"#/components/schemas/object.File"},"id":{"description":"The id of the block","example":"64394517de52ad5acb89c66c","type":"string"},"relation":{"$ref":"#/components/schemas/object.Relation"},"text":{"$ref":"#/components/schemas/object.Text"},"vertical_align":{"description":"The vertical alignment of the block","enum":["VerticalAlignTop","VerticalAlignMiddle","VerticalAlignBottom"],"example":"VerticalAlignTop","type":"string"}},"type":"object"},"object.CreateObjectRequest":{"properties":{"body":{"description":"The body of the object","example":"This is the body of the object. Markdown syntax is supported here.","type":"string"},"description":{"description":"The description of the object","example":"This is a description of the object.","type":"string"},"icon":{"description":"The icon of the object","example":"📄","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object_type_unique_key":{"description":"The unique key of the object type","example":"ot-page","type":"string"},"source":{"description":"The source url, only applicable for bookmarks","example":"https://bookmark-source.com","type":"string"},"template_id":{"description":"The id of the template to use","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"}},"type":"object"},"object.Detail":{"properties":{"details":{"additionalProperties":{},"description":"The details","type":"object"},"id":{"description":"The id of the detail","enum":["last_modified_date","last_modified_by","created_date","created_by","last_opened_date","tags"],"example":"last_modified_date","type":"string"}},"type":"object"},"object.File":{"description":"The file of the block, if applicable","properties":{"added_at":{"description":"The added at of the file","type":"integer"},"hash":{"description":"The hash of the file","type":"string"},"mime":{"description":"The mime of the file","type":"string"},"name":{"description":"The name of the file","type":"string"},"size":{"description":"The size of the file","type":"integer"},"state":{"description":"The state of the file","type":"string"},"style":{"description":"The style of the file","type":"string"},"target_object_id":{"description":"The target object id of the file","type":"string"},"type":{"description":"The type of the file","type":"string"}},"type":"object"},"object.Object":{"description":"The object","properties":{"blocks":{"description":"The blocks of the object","items":{"$ref":"#/components/schemas/object.Block"},"type":"array","uniqueItems":false},"details":{"description":"The details of the object","items":{"$ref":"#/components/schemas/object.Detail"},"type":"array","uniqueItems":false},"icon":{"description":"The icon of the object","example":"📄","type":"string"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"root_id":{"description":"The id of the object's root","example":"bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u","type":"string"},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/object.Type"}},"type":"object"},"object.ObjectResponse":{"properties":{"object":{"$ref":"#/components/schemas/object.Object"}},"type":"object"},"object.Relation":{"description":"The relation of the block, if applicable","properties":{"id":{"type":"string"}},"type":"object"},"object.Template":{"description":"The template","properties":{"icon":{"description":"The icon of the template","example":"📄","type":"string"},"id":{"description":"The id of the template","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"},"name":{"description":"The name of the template","example":"My template","type":"string"},"object":{"description":"The data model of the object","example":"template","type":"string"}},"type":"object"},"object.TemplateResponse":{"properties":{"template":{"$ref":"#/components/schemas/object.Template"}},"type":"object"},"object.Text":{"description":"The text of the block, if applicable","properties":{"checked":{"description":"Whether the text is checked","example":true,"type":"boolean"},"color":{"description":"The color of the text","example":"red","type":"string"},"icon":{"description":"The icon of the text","example":"📄","type":"string"},"style":{"description":"The style of the text","enum":["Paragraph","Header1","Header2","Header3","Header4","Quote","Code","Title","Checkbox","Marked","Numbered","Toggle","Description","Callout"],"example":"Paragraph","type":"string"},"text":{"description":"The text","example":"Some text...","type":"string"}},"type":"object"},"object.Type":{"description":"The type of the object","properties":{"icon":{"description":"The icon of the type","example":"📄","type":"string"},"id":{"description":"The id of the type","example":"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu","type":"string"},"name":{"description":"The name of the type","example":"Page","type":"string"},"object":{"description":"The data model of the object","example":"type","type":"string"},"recommended_layout":{"description":"The recommended layout of the type","example":"todo","type":"string"},"unique_key":{"description":"The unique key of the type","example":"ot-page","type":"string"}},"type":"object"},"object.TypeResponse":{"properties":{"type":{"$ref":"#/components/schemas/object.Type"}},"type":"object"},"pagination.PaginatedResponse-object_Object":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Object"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-object_Template":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Template"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-object_Type":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Type"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-space_Member":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/space.Member"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-space_Space":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/space.Space"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginationMeta":{"description":"The pagination metadata for the response","properties":{"has_more":{"description":"Indicates if there are more items available beyond the current result set","example":true,"type":"boolean"},"limit":{"description":"The maximum number of items returned in the result set","example":100,"type":"integer"},"offset":{"description":"The number of items skipped before starting to collect the result set","example":0,"type":"integer"},"total":{"description":"The total number of items available for the endpoint","example":1024,"type":"integer"}},"type":"object"},"search.SearchRequest":{"properties":{"query":{"description":"The search term to look for in object names and snippets","example":"test","type":"string"},"sort":{"$ref":"#/components/schemas/search.SortOptions"},"types":{"description":"The types of objects to search for, specified by unique key or ID","example":["ot-note","ot-page","ot-678043f0cda9133be777049f","bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"search.SortOptions":{"description":"The sorting criteria and direction for the search results","properties":{"direction":{"default":"desc","description":"The direction to sort the search results","enum":["asc","desc"],"type":"string"},"timestamp":{"default":"last_modified_date","description":"The timestamp to sort the search results by","enum":["created_date","last_modified_date","last_opened_date"],"type":"string"}},"type":"object"},"space.CreateSpaceRequest":{"properties":{"name":{"description":"The name of the space","example":"New Space","type":"string"}},"type":"object"},"space.Member":{"description":"The member","properties":{"global_name":{"description":"The global name of the member in the network","example":"john.any","type":"string"},"icon":{"description":"The icon of the member","example":"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100","type":"string"},"id":{"description":"The profile object id of the member","example":"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ","type":"string"},"identity":{"description":"The identity of the member in the network","example":"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ","type":"string"},"name":{"description":"The name of the member","example":"John Doe","type":"string"},"object":{"description":"The data model of the object","example":"member","type":"string"},"role":{"description":"The role of the member","enum":["Reader","Writer","Owner","NoPermission"],"example":"Owner","type":"string"}},"type":"object"},"space.MemberResponse":{"properties":{"member":{"$ref":"#/components/schemas/space.Member"}},"type":"object"},"space.Space":{"description":"The space","properties":{"account_space_id":{"description":"The id of the account space","example":"bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1","type":"string"},"analytics_id":{"description":"The analytics id of the account","example":"624aecdd-4797-4611-9d61-a2ae5f53cf1c","type":"string"},"archive_object_id":{"description":"The id of the archive object","example":"bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri","type":"string"},"device_id":{"description":"The id of the device","example":"12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF","type":"string"},"gateway_url":{"description":"The gateway url to serve files and media","example":"http://127.0.0.1:31006","type":"string"},"home_object_id":{"description":"The id of the home object","example":"bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya","type":"string"},"icon":{"description":"The icon of the space","example":"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay","type":"string"},"id":{"description":"The id of the space","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"local_storage_path":{"description":"The local storage path of the account","example":"/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha","type":"string"},"marketplace_workspace_id":{"description":"The id of the marketplace workspace","example":"_anytype_marketplace","type":"string"},"name":{"description":"The name of the space","example":"My Space","type":"string"},"network_id":{"description":"The network id of the space","example":"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU","type":"string"},"object":{"description":"The data model of the object","example":"space","type":"string"},"profile_object_id":{"description":"The id of the profile object","example":"bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4","type":"string"},"space_view_id":{"description":"The id of the space view","example":"bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy","type":"string"},"tech_space_id":{"description":"The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself","example":"bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1","type":"string"},"timezone":{"description":"The timezone of the account","example":"","type":"string"},"widgets_id":{"description":"The id of the widgets","example":"bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva","type":"string"},"workspace_object_id":{"description":"The id of the workspace object","example":"bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y","type":"string"}},"type":"object"},"space.SpaceResponse":{"properties":{"space":{"$ref":"#/components/schemas/space.Space"}},"type":"object"},"util.ForbiddenError":{"properties":{"error":{"properties":{"message":{"example":"Forbidden","type":"string"}},"type":"object"}},"type":"object"},"util.NotFoundError":{"properties":{"error":{"properties":{"message":{"example":"Resource not found","type":"string"}},"type":"object"}},"type":"object"},"util.RateLimitError":{"properties":{"error":{"properties":{"message":{"example":"Rate limit exceeded","type":"string"}},"type":"object"}},"type":"object"},"util.ServerError":{"properties":{"error":{"properties":{"message":{"example":"Internal server error","type":"string"}},"type":"object"}},"type":"object"},"util.UnauthorizedError":{"properties":{"error":{"properties":{"message":{"example":"Unauthorized","type":"string"}},"type":"object"}},"type":"object"},"util.ValidationError":{"properties":{"error":{"properties":{"message":{"example":"Bad request","type":"string"}},"type":"object"}},"type":"object"}},"securitySchemes":{"bearerauth":{"bearerFormat":"JWT","scheme":"bearer","type":"http"}}}, "info": {"contact":{"email":"support@anytype.io","name":"Anytype Support","url":"https://anytype.io/contact"},"description":"{{escape .Description}}","license":{"name":"Any Source Available License 1.0","url":"https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md"},"termsOfService":"https://anytype.io/terms_of_use","title":"{{.Title}}","version":"{{.Version}}"}, "externalDocs": {"description":"OpenAPI","url":"https://swagger.io/resources/open-api/"}, - "paths": {"/auth/display_code":{"post":{"parameters":[{"description":"App name requesting the challenge","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.DisplayCodeResponse"}}},"description":"Challenge ID"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["auth"]}},"/auth/token":{"post":{"parameters":[{"description":"Challenge ID","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.TokenResponse"}}},"description":"Authentication token"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Retrieve token","tags":["auth"]}},"/search":{"post":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["search"]}},"/spaces":{"get":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Space"}}},"description":"List of spaces"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["spaces"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.CreateSpaceRequest"}}},"description":"Space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space created successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["spaces"]}},"/spaces/{space_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["spaces"]}},"/spaces/{space_id}/members":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Member"}}},"description":"List of members"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["spaces"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.MemberResponse"}}},"description":"Member"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["spaces"]}},"/spaces/{space_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["objects"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.CreateObjectRequest"}}},"description":"Object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["objects"]},"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The requested object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}/export/{format}":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"Export format","in":"path","name":"format","required":true,"schema":{"enum":["markdown","protobuf"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/export.ObjectExportResponse"}}},"description":"Object exported successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Export object","tags":["export"]}},"/spaces/{space_id}/search":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["search"]}},"/spaces/{space_id}/types":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Type"}}},"description":"List of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["types"]}},"/spaces/{space_id}/types/{type_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Template"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"Template ID","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["types"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["lists"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"List of object IDs","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["lists"]}}}, + "paths": {"/auth/display_code":{"post":{"description":"This endpoint initiates a secure authentication flow by generating a new challenge. Clients must supply the name of the application (via a query parameter) that is requesting authentication. On success, the service returns a unique challenge ID. This challenge ID must then be used with the token endpoint (see below) to solve the challenge and retrieve an authentication token. In essence, this endpoint “boots up” the login process and is the first step in a multi-phase authentication sequence.","parameters":[{"description":"App name requesting the challenge","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.DisplayCodeResponse"}}},"description":"Challenge ID"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["auth"]}},"/auth/token":{"post":{"description":"After receiving a challenge ID from the display_code endpoint, the client calls this endpoint to provide the corresponding 4-digit code (also via a query parameter) along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns an ephemeral session token together with a permanent app key. These tokens are then used in subsequent API requests to authorize access. This endpoint is central to ensuring that only properly authenticated sessions can access further resources.","parameters":[{"description":"Challenge ID","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.TokenResponse"}}},"description":"Authentication token"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Retrieve token","tags":["auth"]}},"/search":{"post":{"description":"This endpoint executes a global search over every space the user has access to. It accepts pagination parameters (offset and limit) and a JSON body containing search criteria. The criteria include a search query string, an optional list of object types, and sort options (e.g. ascending/descending by creation, modification, or last opened dates). Internally, the endpoint aggregates results from each space, merges and sorts them (after last modified date by default), and returns a unified, paginated list of objects that match the search parameters.","parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["search"]}},"/spaces":{"get":{"description":"Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces.","parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Space"}}},"description":"List of spaces"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["spaces"]},"post":{"description":"Creates a new workspace (or space) based on a supplied name in the JSON request body. The endpoint is subject to rate limiting and automatically applies default configurations such as generating a random icon and initializing the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new space.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.CreateSpaceRequest"}}},"description":"Space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space created successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["spaces"]}},"/spaces/{space_id}":{"get":{"description":"Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["spaces"]}},"/spaces/{space_id}/members":{"get":{"description":"Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which may be derived from an emoji or image), network identity, global name, and role (e.g. Reader, Writer, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Member"}}},"description":"List of members"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["spaces"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"description":"Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global name, and role. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.MemberResponse"}}},"description":"Member"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["spaces"]}},"/spaces/{space_id}/objects":{"get":{"description":"Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed data about each object including its ID, name, icon, type information, a snippet of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["objects"]},"post":{"description":"Creates a new object in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include key details such as the object name, icon, description, body content (which may support Markdown), source URL (required for bookmark objects), template identifier, and the unique key for the object type. Post-creation, additional operations (like setting featured relations or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.CreateObjectRequest"}}},"description":"Object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"description":"This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["objects"]},"get":{"description":"Fetches the full details of a single object identified by the object ID within the specified space. The response includes not only basic metadata (ID, name, icon, type) but also the complete set of blocks (which may include text, files, and relations) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The requested object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}/export/{format}":{"post":{"description":"This endpoint exports a single object from the specified space into a desired format. The export format is provided as a path parameter (currently supporting “markdown” and “protobuf”), and clients can optionally specify an export path in the request body. The endpoint calls an export service which converts the object’s content into the requested format and returns the file path where the exported data is stored. It is useful for data backup, sharing, or further processing.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"Export format","in":"path","name":"format","required":true,"schema":{"enum":["markdown","protobuf"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/export.ObjectExportResponse"}}},"description":"Object exported successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Export object","tags":["export"]}},"/spaces/{space_id}/search":{"post":{"description":"This endpoint performs a focused search within a single space (specified by the space_id path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search query, object types, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["search"]}},"/spaces/{space_id}/types":{"get":{"description":"This endpoint retrieves a paginated list of object types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, unique key, display name, icon, and a recommended layout. Clients use this information when offering choices for object creation or for filtering objects by type.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Type"}}},"description":"List of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["types"]}},"/spaces/{space_id}/types/{type_id}":{"get":{"description":"Fetches detailed information about one specific object type by its ID. This includes the type’s unique key, name, icon, and recommended layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints).","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"description":"This endpoint returns a paginated list of templates that are associated with a specific object type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Template"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"description":"Fetches full details for one template associated with a particular object type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"Template ID","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["types"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"get":{"description":"Returns a paginated list of objects that are associated with a specific list (or collection) within a space. This endpoint helps clients to manage grouped objects (for example, tasks within a list) by returning detailed object information for each item of the list.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["lists"]},"post":{"description":"Enables clients to add one or more objects to a specific list by submitting a JSON array of object IDs. Upon success, the endpoint returns a confirmation message. This endpoint is vital for building user interfaces that allow drag‑and‑drop or multi‑select additions to collections.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"List of object IDs","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"description":"Removes a given object from the specified list in a space. The endpoint takes the space, list, and object identifiers as path parameters. It's subject to rate limiting and returns a success message on completion. It is used for dynamically managing collections without affecting the underlying object data.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["lists"]}}}, "openapi": "3.1.0", "servers": [ {"url":"http://localhost:31009/v1"} diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json index 3247b1acfb..903f69158a 100644 --- a/core/api/docs/swagger.json +++ b/core/api/docs/swagger.json @@ -2,7 +2,7 @@ "components": {"schemas":{"auth.DisplayCodeResponse":{"properties":{"challenge_id":{"description":"The challenge id associated with the displayed code and needed to solve the challenge for token","example":"67647f5ecda913e9a2e11b26","type":"string"}},"type":"object"},"auth.TokenResponse":{"properties":{"app_key":{"description":"The permanent app key","example":"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=","type":"string"},"session_token":{"description":"The ephemeral session token","example":"eyJhbGciOeJIRzI1NiIsInR5cCI6IkpXVCJ1.eyJzZWVkIjaiY0dmVndlUnAifQ.Y1EZecYnwmvMkrXKOa2XJnAbaRt34urBabe06tmDQII","type":"string"}},"type":"object"},"export.ObjectExportResponse":{"properties":{"path":{"description":"The path the object was exported to","example":"/path/to/export","type":"string"}},"type":"object"},"object.Block":{"properties":{"align":{"description":"The alignment of the block","enum":["AlignLeft","AlignCenter","AlignRight","AlignJustify"],"example":"AlignLeft","type":"string"},"background_color":{"description":"The background color of the block","example":"red","type":"string"},"children_ids":{"description":"The ids of the block's children","example":["['6797ce8ecda913cde14b02dc']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"file":{"$ref":"#/components/schemas/object.File"},"id":{"description":"The id of the block","example":"64394517de52ad5acb89c66c","type":"string"},"relation":{"$ref":"#/components/schemas/object.Relation"},"text":{"$ref":"#/components/schemas/object.Text"},"vertical_align":{"description":"The vertical alignment of the block","enum":["VerticalAlignTop","VerticalAlignMiddle","VerticalAlignBottom"],"example":"VerticalAlignTop","type":"string"}},"type":"object"},"object.CreateObjectRequest":{"properties":{"body":{"description":"The body of the object","example":"This is the body of the object. Markdown syntax is supported here.","type":"string"},"description":{"description":"The description of the object","example":"This is a description of the object.","type":"string"},"icon":{"description":"The icon of the object","example":"📄","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object_type_unique_key":{"description":"The unique key of the object type","example":"ot-page","type":"string"},"source":{"description":"The source url, only applicable for bookmarks","example":"https://bookmark-source.com","type":"string"},"template_id":{"description":"The id of the template to use","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"}},"type":"object"},"object.Detail":{"properties":{"details":{"additionalProperties":{},"description":"The details","type":"object"},"id":{"description":"The id of the detail","enum":["last_modified_date","last_modified_by","created_date","created_by","last_opened_date","tags"],"example":"last_modified_date","type":"string"}},"type":"object"},"object.File":{"description":"The file of the block, if applicable","properties":{"added_at":{"description":"The added at of the file","type":"integer"},"hash":{"description":"The hash of the file","type":"string"},"mime":{"description":"The mime of the file","type":"string"},"name":{"description":"The name of the file","type":"string"},"size":{"description":"The size of the file","type":"integer"},"state":{"description":"The state of the file","type":"string"},"style":{"description":"The style of the file","type":"string"},"target_object_id":{"description":"The target object id of the file","type":"string"},"type":{"description":"The type of the file","type":"string"}},"type":"object"},"object.Object":{"description":"The object","properties":{"blocks":{"description":"The blocks of the object","items":{"$ref":"#/components/schemas/object.Block"},"type":"array","uniqueItems":false},"details":{"description":"The details of the object","items":{"$ref":"#/components/schemas/object.Detail"},"type":"array","uniqueItems":false},"icon":{"description":"The icon of the object","example":"📄","type":"string"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"root_id":{"description":"The id of the object's root","example":"bafyreicypzj6uvu54664ucv3hmbsd5cmdy2dv4fwua26sciq74khzpyn4u","type":"string"},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/object.Type"}},"type":"object"},"object.ObjectResponse":{"properties":{"object":{"$ref":"#/components/schemas/object.Object"}},"type":"object"},"object.Relation":{"description":"The relation of the block, if applicable","properties":{"id":{"type":"string"}},"type":"object"},"object.Template":{"description":"The template","properties":{"icon":{"description":"The icon of the template","example":"📄","type":"string"},"id":{"description":"The id of the template","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"},"name":{"description":"The name of the template","example":"My template","type":"string"},"object":{"description":"The data model of the object","example":"template","type":"string"}},"type":"object"},"object.TemplateResponse":{"properties":{"template":{"$ref":"#/components/schemas/object.Template"}},"type":"object"},"object.Text":{"description":"The text of the block, if applicable","properties":{"checked":{"description":"Whether the text is checked","example":true,"type":"boolean"},"color":{"description":"The color of the text","example":"red","type":"string"},"icon":{"description":"The icon of the text","example":"📄","type":"string"},"style":{"description":"The style of the text","enum":["Paragraph","Header1","Header2","Header3","Header4","Quote","Code","Title","Checkbox","Marked","Numbered","Toggle","Description","Callout"],"example":"Paragraph","type":"string"},"text":{"description":"The text","example":"Some text...","type":"string"}},"type":"object"},"object.Type":{"description":"The type of the object","properties":{"icon":{"description":"The icon of the type","example":"📄","type":"string"},"id":{"description":"The id of the type","example":"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu","type":"string"},"name":{"description":"The name of the type","example":"Page","type":"string"},"object":{"description":"The data model of the object","example":"type","type":"string"},"recommended_layout":{"description":"The recommended layout of the type","example":"todo","type":"string"},"unique_key":{"description":"The unique key of the type","example":"ot-page","type":"string"}},"type":"object"},"object.TypeResponse":{"properties":{"type":{"$ref":"#/components/schemas/object.Type"}},"type":"object"},"pagination.PaginatedResponse-object_Object":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Object"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-object_Template":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Template"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-object_Type":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/object.Type"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-space_Member":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/space.Member"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-space_Space":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/space.Space"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginationMeta":{"description":"The pagination metadata for the response","properties":{"has_more":{"description":"Indicates if there are more items available beyond the current result set","example":true,"type":"boolean"},"limit":{"description":"The maximum number of items returned in the result set","example":100,"type":"integer"},"offset":{"description":"The number of items skipped before starting to collect the result set","example":0,"type":"integer"},"total":{"description":"The total number of items available for the endpoint","example":1024,"type":"integer"}},"type":"object"},"search.SearchRequest":{"properties":{"query":{"description":"The search term to look for in object names and snippets","example":"test","type":"string"},"sort":{"$ref":"#/components/schemas/search.SortOptions"},"types":{"description":"The types of objects to search for, specified by unique key or ID","example":["ot-note","ot-page","ot-678043f0cda9133be777049f","bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"search.SortOptions":{"description":"The sorting criteria and direction for the search results","properties":{"direction":{"default":"desc","description":"The direction to sort the search results","enum":["asc","desc"],"type":"string"},"timestamp":{"default":"last_modified_date","description":"The timestamp to sort the search results by","enum":["created_date","last_modified_date","last_opened_date"],"type":"string"}},"type":"object"},"space.CreateSpaceRequest":{"properties":{"name":{"description":"The name of the space","example":"New Space","type":"string"}},"type":"object"},"space.Member":{"description":"The member","properties":{"global_name":{"description":"The global name of the member in the network","example":"john.any","type":"string"},"icon":{"description":"The icon of the member","example":"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay?width=100","type":"string"},"id":{"description":"The profile object id of the member","example":"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ","type":"string"},"identity":{"description":"The identity of the member in the network","example":"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ","type":"string"},"name":{"description":"The name of the member","example":"John Doe","type":"string"},"object":{"description":"The data model of the object","example":"member","type":"string"},"role":{"description":"The role of the member","enum":["Reader","Writer","Owner","NoPermission"],"example":"Owner","type":"string"}},"type":"object"},"space.MemberResponse":{"properties":{"member":{"$ref":"#/components/schemas/space.Member"}},"type":"object"},"space.Space":{"description":"The space","properties":{"account_space_id":{"description":"The id of the account space","example":"bafyreihpd2knon5wbljhtfeg3fcqtg3i2pomhhnigui6lrjmzcjzep7gcy.23me69r569oi1","type":"string"},"analytics_id":{"description":"The analytics id of the account","example":"624aecdd-4797-4611-9d61-a2ae5f53cf1c","type":"string"},"archive_object_id":{"description":"The id of the archive object","example":"bafyreialsgoyflf3etjm3parzurivyaukzivwortf32b4twnlwpwocsrri","type":"string"},"device_id":{"description":"The id of the device","example":"12D3KooWGZMJ4kQVyQVXaj7gJPZr3RZ2nvd9M2Eq2pprEoPih9WF","type":"string"},"gateway_url":{"description":"The gateway url to serve files and media","example":"http://127.0.0.1:31006","type":"string"},"home_object_id":{"description":"The id of the home object","example":"bafyreie4qcl3wczb4cw5hrfyycikhjyh6oljdis3ewqrk5boaav3sbwqya","type":"string"},"icon":{"description":"The icon of the space","example":"http://127.0.0.1:31006/image/bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay","type":"string"},"id":{"description":"The id of the space","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"local_storage_path":{"description":"The local storage path of the account","example":"/Users/johndoe/Library/Application Support/Anytype/data/AAHTtt1wuQEnaYBNZ2Cyfcvs6DqPqxgn8VXDVk4avsUkMuha","type":"string"},"marketplace_workspace_id":{"description":"The id of the marketplace workspace","example":"_anytype_marketplace","type":"string"},"name":{"description":"The name of the space","example":"My Space","type":"string"},"network_id":{"description":"The network id of the space","example":"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU","type":"string"},"object":{"description":"The data model of the object","example":"space","type":"string"},"profile_object_id":{"description":"The id of the profile object","example":"bafyreiaxhwreshjqwndpwtdsu4mtihaqhhmlygqnyqpfyfwlqfq3rm3gw4","type":"string"},"space_view_id":{"description":"The id of the space view","example":"bafyreigzv3vq7qwlrsin6njoduq727ssnhwd6bgyfj6nm4hv3pxoc2rxhy","type":"string"},"tech_space_id":{"description":"The id of tech space, where objects outside of user's actual spaces are stored, e.g. spaces itself","example":"bafyreif4xuwncrjl6jajt4zrrfnylpki476nv2w64yf42ovt7gia7oypii.23me69r569oi1","type":"string"},"timezone":{"description":"The timezone of the account","example":"","type":"string"},"widgets_id":{"description":"The id of the widgets","example":"bafyreialj7pceh53mifm5dixlho47ke4qjmsn2uh4wsjf7xq2pnlo5xfva","type":"string"},"workspace_object_id":{"description":"The id of the workspace object","example":"bafyreiapey2g6e6za4zfxvlgwdy4hbbfu676gmwrhnqvjbxvrchr7elr3y","type":"string"}},"type":"object"},"space.SpaceResponse":{"properties":{"space":{"$ref":"#/components/schemas/space.Space"}},"type":"object"},"util.ForbiddenError":{"properties":{"error":{"properties":{"message":{"example":"Forbidden","type":"string"}},"type":"object"}},"type":"object"},"util.NotFoundError":{"properties":{"error":{"properties":{"message":{"example":"Resource not found","type":"string"}},"type":"object"}},"type":"object"},"util.RateLimitError":{"properties":{"error":{"properties":{"message":{"example":"Rate limit exceeded","type":"string"}},"type":"object"}},"type":"object"},"util.ServerError":{"properties":{"error":{"properties":{"message":{"example":"Internal server error","type":"string"}},"type":"object"}},"type":"object"},"util.UnauthorizedError":{"properties":{"error":{"properties":{"message":{"example":"Unauthorized","type":"string"}},"type":"object"}},"type":"object"},"util.ValidationError":{"properties":{"error":{"properties":{"message":{"example":"Bad request","type":"string"}},"type":"object"}},"type":"object"}},"securitySchemes":{"bearerauth":{"bearerFormat":"JWT","scheme":"bearer","type":"http"}}}, "info": {"contact":{"email":"support@anytype.io","name":"Anytype Support","url":"https://anytype.io/contact"},"description":"This API allows interaction with Anytype resources such as spaces, objects and types.","license":{"name":"Any Source Available License 1.0","url":"https://github.com/anyproto/anytype-ts/blob/main/LICENSE.md"},"termsOfService":"https://anytype.io/terms_of_use","title":"Anytype API","version":"1.0"}, "externalDocs": {"description":"OpenAPI","url":"https://swagger.io/resources/open-api/"}, - "paths": {"/auth/display_code":{"post":{"parameters":[{"description":"App name requesting the challenge","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.DisplayCodeResponse"}}},"description":"Challenge ID"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["auth"]}},"/auth/token":{"post":{"parameters":[{"description":"Challenge ID","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.TokenResponse"}}},"description":"Authentication token"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Retrieve token","tags":["auth"]}},"/search":{"post":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["search"]}},"/spaces":{"get":{"parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Space"}}},"description":"List of spaces"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["spaces"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.CreateSpaceRequest"}}},"description":"Space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space created successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["spaces"]}},"/spaces/{space_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["spaces"]}},"/spaces/{space_id}/members":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Member"}}},"description":"List of members"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["spaces"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.MemberResponse"}}},"description":"Member"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["spaces"]}},"/spaces/{space_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["objects"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.CreateObjectRequest"}}},"description":"Object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["objects"]},"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The requested object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}/export/{format}":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"Export format","in":"path","name":"format","required":true,"schema":{"enum":["markdown","protobuf"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/export.ObjectExportResponse"}}},"description":"Object exported successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Export object","tags":["export"]}},"/spaces/{space_id}/search":{"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["search"]}},"/spaces/{space_id}/types":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Type"}}},"description":"List of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["types"]}},"/spaces/{space_id}/types/{type_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Template"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"Template ID","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["types"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"get":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["lists"]},"post":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"List of object IDs","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["lists"]}}}, + "paths": {"/auth/display_code":{"post":{"description":"This endpoint initiates a secure authentication flow by generating a new challenge. Clients must supply the name of the application (via a query parameter) that is requesting authentication. On success, the service returns a unique challenge ID. This challenge ID must then be used with the token endpoint (see below) to solve the challenge and retrieve an authentication token. In essence, this endpoint “boots up” the login process and is the first step in a multi-phase authentication sequence.","parameters":[{"description":"App name requesting the challenge","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.DisplayCodeResponse"}}},"description":"Challenge ID"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["auth"]}},"/auth/token":{"post":{"description":"After receiving a challenge ID from the display_code endpoint, the client calls this endpoint to provide the corresponding 4-digit code (also via a query parameter) along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns an ephemeral session token together with a permanent app key. These tokens are then used in subsequent API requests to authorize access. This endpoint is central to ensuring that only properly authenticated sessions can access further resources.","parameters":[{"description":"Challenge ID","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/auth.TokenResponse"}}},"description":"Authentication token"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Retrieve token","tags":["auth"]}},"/search":{"post":{"description":"This endpoint executes a global search over every space the user has access to. It accepts pagination parameters (offset and limit) and a JSON body containing search criteria. The criteria include a search query string, an optional list of object types, and sort options (e.g. ascending/descending by creation, modification, or last opened dates). Internally, the endpoint aggregates results from each space, merges and sorts them (after last modified date by default), and returns a unified, paginated list of objects that match the search parameters.","parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["search"]}},"/spaces":{"get":{"description":"Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces.","parameters":[{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Space"}}},"description":"List of spaces"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["spaces"]},"post":{"description":"Creates a new workspace (or space) based on a supplied name in the JSON request body. The endpoint is subject to rate limiting and automatically applies default configurations such as generating a random icon and initializing the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new space.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.CreateSpaceRequest"}}},"description":"Space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space created successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["spaces"]}},"/spaces/{space_id}":{"get":{"description":"Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.SpaceResponse"}}},"description":"Space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["spaces"]}},"/spaces/{space_id}/members":{"get":{"description":"Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which may be derived from an emoji or image), network identity, global name, and role (e.g. Reader, Writer, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-space_Member"}}},"description":"List of members"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["spaces"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"description":"Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global name, and role. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/space.MemberResponse"}}},"description":"Member"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["spaces"]}},"/spaces/{space_id}/objects":{"get":{"description":"Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed data about each object including its ID, name, icon, type information, a snippet of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["objects"]},"post":{"description":"Creates a new object in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include key details such as the object name, icon, description, body content (which may support Markdown), source URL (required for bookmark objects), template identifier, and the unique key for the object type. Post-creation, additional operations (like setting featured relations or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.CreateObjectRequest"}}},"description":"Object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"description":"This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"423":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["objects"]},"get":{"description":"Fetches the full details of a single object identified by the object ID within the specified space. The response includes not only basic metadata (ID, name, icon, type) but also the complete set of blocks (which may include text, files, and relations) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.ObjectResponse"}}},"description":"The requested object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["objects"]}},"/spaces/{space_id}/objects/{object_id}/export/{format}":{"post":{"description":"This endpoint exports a single object from the specified space into a desired format. The export format is provided as a path parameter (currently supporting “markdown” and “protobuf”), and clients can optionally specify an export path in the request body. The endpoint calls an export service which converts the object’s content into the requested format and returns the file path where the exported data is stored. It is useful for data backup, sharing, or further processing.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"Export format","in":"path","name":"format","required":true,"schema":{"enum":["markdown","protobuf"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/export.ObjectExportResponse"}}},"description":"Object exported successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Export object","tags":["export"]}},"/spaces/{space_id}/search":{"post":{"description":"This endpoint performs a focused search within a single space (specified by the space_id path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search query, object types, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/search.SearchRequest"}}},"description":"Search parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["search"]}},"/spaces/{space_id}/types":{"get":{"description":"This endpoint retrieves a paginated list of object types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, unique key, display name, icon, and a recommended layout. Clients use this information when offering choices for object creation or for filtering objects by type.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Type"}}},"description":"List of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["types"]}},"/spaces/{space_id}/types/{type_id}":{"get":{"description":"Fetches detailed information about one specific object type by its ID. This includes the type’s unique key, name, icon, and recommended layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints).","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"description":"This endpoint returns a paginated list of templates that are associated with a specific object type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Template"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["types"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"description":"Fetches full details for one template associated with a particular object type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Type ID","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"Template ID","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/object.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["types"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"get":{"description":"Returns a paginated list of objects that are associated with a specific list (or collection) within a space. This endpoint helps clients to manage grouped objects (for example, tasks within a list) by returning detailed object information for each item of the list.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-object_Object"}}},"description":"List of objects"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["lists"]},"post":{"description":"Enables clients to add one or more objects to a specific list by submitting a JSON array of object IDs. Upon success, the endpoint returns a confirmation message. This endpoint is vital for building user interfaces that allow drag‑and‑drop or multi‑select additions to collections.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"List of object IDs","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"description":"Removes a given object from the specified list in a space. The endpoint takes the space, list, and object identifiers as path parameters. It's subject to rate limiting and returns a success message on completion. It is used for dynamically managing collections without affecting the underlying object data.","parameters":[{"description":"Space ID","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"List ID","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"Object ID","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["lists"]}}}, "openapi": "3.1.0", "servers": [ {"url":"http://localhost:31009/v1"} diff --git a/core/api/docs/swagger.yaml b/core/api/docs/swagger.yaml index 2c3ff7a8e8..13e0363eba 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/swagger.yaml @@ -638,6 +638,13 @@ openapi: 3.1.0 paths: /auth/display_code: post: + description: This endpoint initiates a secure authentication flow by generating + a new challenge. Clients must supply the name of the application (via a query + parameter) that is requesting authentication. On success, the service returns + a unique challenge ID. This challenge ID must then be used with the token + endpoint (see below) to solve the challenge and retrieve an authentication + token. In essence, this endpoint “boots up” the login process and is the first + step in a multi-phase authentication sequence. parameters: - description: App name requesting the challenge in: query @@ -674,6 +681,13 @@ paths: - auth /auth/token: post: + description: After receiving a challenge ID from the display_code endpoint, + the client calls this endpoint to provide the corresponding 4-digit code (also + via a query parameter) along with the challenge ID. The endpoint verifies + that the challenge solution is correct and, if it is, returns an ephemeral + session token together with a permanent app key. These tokens are then used + in subsequent API requests to authorize access. This endpoint is central to + ensuring that only properly authenticated sessions can access further resources. parameters: - description: Challenge ID in: query @@ -716,6 +730,14 @@ paths: - auth /search: post: + description: This endpoint executes a global search over every space the user + has access to. It accepts pagination parameters (offset and limit) and a JSON + body containing search criteria. The criteria include a search query string, + an optional list of object types, and sort options (e.g. ascending/descending + by creation, modification, or last opened dates). Internally, the endpoint + aggregates results from each space, merges and sorts them (after last modified + date by default), and returns a unified, paginated list of objects that match + the search parameters. parameters: - description: The number of items to skip before starting to collect the result set @@ -764,6 +786,10 @@ paths: - search /spaces: get: + description: Retrieves a paginated list of all spaces that are accessible by + the authenticated user. Each space record contains detailed information such + as the space ID, name, icon (derived either from an emoji or image URL), and + additional metadata. This endpoint is key to displaying a user’s workspaces. parameters: - description: The number of items to skip before starting to collect the result set @@ -804,6 +830,12 @@ paths: tags: - spaces post: + description: Creates a new workspace (or space) based on a supplied name in + the JSON request body. The endpoint is subject to rate limiting and automatically + applies default configurations such as generating a random icon and initializing + the workspace with default settings (for example, a default dashboard or home + page). On success, the new space’s full metadata is returned, enabling the + client to immediately switch context to the new space. requestBody: content: application/json: @@ -849,6 +881,10 @@ paths: - spaces /spaces/{space_id}: get: + description: Fetches full details about a single space identified by its space + ID. The response includes metadata such as the space name, icon, and various + workspace IDs (home, archive, profile, etc.). This detailed view supports + use cases such as displaying space-specific settings. parameters: - description: Space ID in: path @@ -888,6 +924,11 @@ paths: - spaces /spaces/{space_id}/members: get: + description: Returns a paginated list of members belonging to the specified + space. Each member record includes the member’s profile ID, name, icon (which + may be derived from an emoji or image), network identity, global name, and + role (e.g. Reader, Writer, Owner). This endpoint supports collaborative features + by allowing clients to show who is in a space and manage access rights. parameters: - description: Space ID in: path @@ -935,6 +976,10 @@ paths: - spaces /spaces/{space_id}/members/{member_id}: get: + description: Fetches detailed information about a single member within a space. + The endpoint returns the member’s identifier, name, icon, identity, global + name, and role. This is useful for user profile pages, permission management, + and displaying member-specific information in collaborative environments. parameters: - description: Space ID in: path @@ -980,6 +1025,12 @@ paths: - spaces /spaces/{space_id}/objects: get: + description: Retrieves a paginated list of objects in the given space. The endpoint + takes query parameters for pagination (offset and limit) and returns detailed + data about each object including its ID, name, icon, type information, a snippet + of the content (if applicable), layout, space ID, blocks and details. It is + intended for building views where users can see all objects in a space at + a glance. parameters: - description: Space ID in: path @@ -1026,6 +1077,14 @@ paths: tags: - objects post: + description: Creates a new object in the specified space using a JSON payload. + The creation process is subject to rate limiting. The payload must include + key details such as the object name, icon, description, body content (which + may support Markdown), source URL (required for bookmark objects), template + identifier, and the unique key for the object type. Post-creation, additional + operations (like setting featured relations or fetching bookmark metadata) + may occur. The endpoint then returns the full object data, ready for further + interactions. parameters: - description: Space ID in: path @@ -1078,6 +1137,11 @@ paths: - objects /spaces/{space_id}/objects/{object_id}: delete: + description: This endpoint “deletes” an object by marking it as archived. The + deletion process is performed safely and is subject to rate limiting. It returns + the object’s details after it has been archived. Proper error handling is + in place for situations such as when the object isn’t found or the deletion + cannot be performed because of permission issues. parameters: - description: Space ID in: path @@ -1134,6 +1198,12 @@ paths: tags: - objects get: + description: Fetches the full details of a single object identified by the object + ID within the specified space. The response includes not only basic metadata + (ID, name, icon, type) but also the complete set of blocks (which may include + text, files, and relations) and extra details (such as timestamps and linked + member information). This endpoint is essential when a client needs to render + or edit the full object view. parameters: - description: Space ID in: path @@ -1179,6 +1249,13 @@ paths: - objects /spaces/{space_id}/objects/{object_id}/export/{format}: post: + description: This endpoint exports a single object from the specified space + into a desired format. The export format is provided as a path parameter (currently + supporting “markdown” and “protobuf”), and clients can optionally specify + an export path in the request body. The endpoint calls an export service which + converts the object’s content into the requested format and returns the file + path where the exported data is stored. It is useful for data backup, sharing, + or further processing. parameters: - description: Space ID in: path @@ -1238,6 +1315,12 @@ paths: - export /spaces/{space_id}/search: post: + description: This endpoint performs a focused search within a single space (specified + by the space_id path parameter). Like the global search, it accepts pagination + parameters and a JSON payload containing the search query, object types, and + sorting preferences. The search is limited to the provided space and returns + a list of objects that match the query. This allows clients to implement space‑specific + filtering without having to process extraneous results. parameters: - description: Space ID in: path @@ -1292,6 +1375,11 @@ paths: - search /spaces/{space_id}/types: get: + description: This endpoint retrieves a paginated list of object types (e.g. + 'Page', 'Note', 'Task') available within the specified space. Each type’s + record includes its unique identifier, unique key, display name, icon, and + a recommended layout. Clients use this information when offering choices for + object creation or for filtering objects by type. parameters: - description: Space ID in: path @@ -1339,6 +1427,11 @@ paths: - types /spaces/{space_id}/types/{type_id}: get: + description: Fetches detailed information about one specific object type by + its ID. This includes the type’s unique key, name, icon, and recommended layout. + This detailed view assists clients in understanding the expected structure + and style for objects of that type and in guiding the user interface (such + as displaying appropriate icons or layout hints). parameters: - description: Space ID in: path @@ -1384,6 +1477,11 @@ paths: - types /spaces/{space_id}/types/{type_id}/templates: get: + description: This endpoint returns a paginated list of templates that are associated + with a specific object type within a space. Templates provide pre‑configured + structures for creating new objects. Each template record contains its identifier, + name, and icon, so that clients can offer users a selection of templates when + creating objects. parameters: - description: Space ID in: path @@ -1437,6 +1535,10 @@ paths: - types /spaces/{space_id}/types/{type_id}/templates/{template_id}: get: + description: Fetches full details for one template associated with a particular + object type in a space. The response provides the template’s identifier, name, + icon, and any other relevant metadata. This endpoint is useful when a client + needs to preview or apply a template to prefill object creation fields. parameters: - description: Space ID in: path @@ -1488,6 +1590,10 @@ paths: - types /v1/spaces/{space_id}/lists/{list_id}/objects: get: + description: Returns a paginated list of objects that are associated with a + specific list (or collection) within a space. This endpoint helps clients + to manage grouped objects (for example, tasks within a list) by returning + detailed object information for each item of the list. parameters: - description: Space ID in: path @@ -1544,6 +1650,10 @@ paths: tags: - lists post: + description: Enables clients to add one or more objects to a specific list by + submitting a JSON array of object IDs. Upon success, the endpoint returns + a confirmation message. This endpoint is vital for building user interfaces + that allow drag‑and‑drop or multi‑select additions to collections. parameters: - description: Space ID in: path @@ -1604,6 +1714,11 @@ paths: - lists /v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}: delete: + description: Removes a given object from the specified list in a space. The + endpoint takes the space, list, and object identifiers as path parameters. + It's subject to rate limiting and returns a success message on completion. + It is used for dynamically managing collections without affecting the underlying + object data. parameters: - description: Space ID in: path diff --git a/core/api/internal/auth/handler.go b/core/api/internal/auth/handler.go index 21900c9946..46cdbb1887 100644 --- a/core/api/internal/auth/handler.go +++ b/core/api/internal/auth/handler.go @@ -10,15 +10,16 @@ import ( // DisplayCodeHandler starts a new challenge and returns the challenge ID // -// @Summary Start new challenge -// @Tags auth -// @Accept json -// @Produce json -// @Param app_name query string true "App name requesting the challenge" -// @Success 200 {object} DisplayCodeResponse "Challenge ID" -// @Failure 400 {object} util.ValidationError "Invalid input" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Router /auth/display_code [post] +// @Summary Start new challenge +// @Description This endpoint initiates a secure authentication flow by generating a new challenge. Clients must supply the name of the application (via a query parameter) that is requesting authentication. On success, the service returns a unique challenge ID. This challenge ID must then be used with the token endpoint (see below) to solve the challenge and retrieve an authentication token. In essence, this endpoint “boots up” the login process and is the first step in a multi-phase authentication sequence. +// @Tags auth +// @Accept json +// @Produce json +// @Param app_name query string true "App name requesting the challenge" +// @Success 200 {object} DisplayCodeResponse "Challenge ID" +// @Failure 400 {object} util.ValidationError "Invalid input" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /auth/display_code [post] func DisplayCodeHandler(s *AuthService) gin.HandlerFunc { return func(c *gin.Context) { appName := c.Query("app_name") @@ -40,16 +41,17 @@ func DisplayCodeHandler(s *AuthService) gin.HandlerFunc { // TokenHandler retrieves an authentication token using a code and challenge ID // -// @Summary Retrieve token -// @Tags auth -// @Accept json -// @Produce json -// @Param challenge_id query string true "Challenge ID" -// @Param code query string true "4-digit code retrieved from Anytype Desktop app" -// @Success 200 {object} TokenResponse "Authentication token" -// @Failure 400 {object} util.ValidationError "Invalid input" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Router /auth/token [post] +// @Summary Retrieve token +// @Description After receiving a challenge ID from the display_code endpoint, the client calls this endpoint to provide the corresponding 4-digit code (also via a query parameter) along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns an ephemeral session token together with a permanent app key. These tokens are then used in subsequent API requests to authorize access. This endpoint is central to ensuring that only properly authenticated sessions can access further resources. +// @Tags auth +// @Accept json +// @Produce json +// @Param challenge_id query string true "Challenge ID" +// @Param code query string true "4-digit code retrieved from Anytype Desktop app" +// @Success 200 {object} TokenResponse "Authentication token" +// @Failure 400 {object} util.ValidationError "Invalid input" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /auth/token [post] func TokenHandler(s *AuthService) gin.HandlerFunc { return func(c *gin.Context) { challengeId := c.Query("challenge_id") diff --git a/core/api/internal/export/handler.go b/core/api/internal/export/handler.go index b0a2813a42..cc4c058134 100644 --- a/core/api/internal/export/handler.go +++ b/core/api/internal/export/handler.go @@ -10,19 +10,20 @@ import ( // GetObjectExportHandler exports an object in specified format // -// @Summary Export object -// @Tags export -// @Accept json -// @Produce json -// @Param space_id path string true "Space ID" -// @Param object_id path string true "Object ID" -// @Param format path string true "Export format" Enums(markdown,protobuf) -// @Success 200 {object} ObjectExportResponse "Object exported successfully" -// @Failure 400 {object} util.ValidationError "Bad request" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/objects/{object_id}/export/{format} [post] +// @Summary Export object +// @Description This endpoint exports a single object from the specified space into a desired format. The export format is provided as a path parameter (currently supporting “markdown” and “protobuf”), and clients can optionally specify an export path in the request body. The endpoint calls an export service which converts the object’s content into the requested format and returns the file path where the exported data is stored. It is useful for data backup, sharing, or further processing. +// @Tags export +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param object_id path string true "Object ID" +// @Param format path string true "Export format" Enums(markdown,protobuf) +// @Success 200 {object} ObjectExportResponse "Object exported successfully" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/objects/{object_id}/export/{format} [post] func GetObjectExportHandler(s *ExportService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/internal/list/handler.go b/core/api/internal/list/handler.go index c5c6871ae5..761795a117 100644 --- a/core/api/internal/list/handler.go +++ b/core/api/internal/list/handler.go @@ -11,19 +11,20 @@ import ( // GetObjectsInListHandler // -// @Summary Get objects in list -// @Tags lists -// @Produce json -// @Param space_id path string true "Space ID" -// @Param list_id path string true "List ID" -// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) -// @Param limit query int false "The number of items to return" -// @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [get] +// @Summary Get objects in list +// @Description Returns a paginated list of objects that are associated with a specific list (or collection) within a space. This endpoint helps clients to manage grouped objects (for example, tasks within a list) by returning detailed object information for each item of the list. +// @Tags lists +// @Produce json +// @Param space_id path string true "Space ID" +// @Param list_id path string true "List ID" +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" +// @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [get] func GetObjectsInListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -48,20 +49,21 @@ func GetObjectsInListHandler(s *ListService) gin.HandlerFunc { // AddObjectsToListHandler // -// @Summary Add objects to list -// @Tags lists -// @Accept json -// @Produce json -// @Param space_id path string true "Space ID" -// @Param list_id path string true "List ID" -// @Param objects body []string true "List of object IDs" -// @Success 200 {object} string "Objects added successfully" -// @Failure 400 {object} util.ValidationError "Bad request" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [post] +// @Summary Add objects to list +// @Description Enables clients to add one or more objects to a specific list by submitting a JSON array of object IDs. Upon success, the endpoint returns a confirmation message. This endpoint is vital for building user interfaces that allow drag‑and‑drop or multi‑select additions to collections. +// @Tags lists +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param list_id path string true "List ID" +// @Param objects body []string true "List of object IDs" +// @Success 200 {object} string "Objects added successfully" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [post] func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -91,19 +93,20 @@ func AddObjectsToListHandler(s *ListService) gin.HandlerFunc { // RemoveObjectFromListHandler // -// @Summary Remove object from list -// @Tags lists -// @Produce json -// @Param space_id path string true "Space ID" -// @Param list_id path string true "List ID" -// @Param object_id path string true "Object ID" -// @Success 200 {object} string "Objects removed successfully" -// @Failure 400 {object} util.ValidationError "Bad request" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /v1/spaces/{space_id}/lists/{list_id}/objects/{object_id} [delete] +// @Summary Remove object from list +// @Description Removes a given object from the specified list in a space. The endpoint takes the space, list, and object identifiers as path parameters. It's subject to rate limiting and returns a success message on completion. It is used for dynamically managing collections without affecting the underlying object data. +// @Tags lists +// @Produce json +// @Param space_id path string true "Space ID" +// @Param list_id path string true "List ID" +// @Param object_id path string true "Object ID" +// @Success 200 {object} string "Objects removed successfully" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects/{object_id} [delete] func RemoveObjectFromListHandler(s *ListService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/internal/object/handler.go b/core/api/internal/object/handler.go index a8a0aa25d1..c62f18768e 100644 --- a/core/api/internal/object/handler.go +++ b/core/api/internal/object/handler.go @@ -11,17 +11,18 @@ import ( // GetObjectsHandler retrieves a list of objects in a space // -// @Summary List objects -// @Tags objects -// @Produce json -// @Param space_id path string true "Space ID" -// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) -// @Param limit query int false "The number of items to return" default(100) maximum(1000) -// @Success 200 {object} pagination.PaginatedResponse[Object] "List of objects" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/objects [get] +// @Summary List objects +// @Description Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed data about each object including its ID, name, icon, type information, a snippet of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance. +// @Tags objects +// @Produce json +// @Param space_id path string true "Space ID" +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" default(100) maximum(1000) +// @Success 200 {object} pagination.PaginatedResponse[Object] "List of objects" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/objects [get] func GetObjectsHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -47,17 +48,18 @@ func GetObjectsHandler(s *ObjectService) gin.HandlerFunc { // GetObjectHandler retrieves an object in a space // -// @Summary Get object -// @Tags objects -// @Produce json -// @Param space_id path string true "Space ID" -// @Param object_id path string true "Object ID" -// @Success 200 {object} ObjectResponse "The requested object" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Resource not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/objects/{object_id} [get] +// @Summary Get object +// @Description Fetches the full details of a single object identified by the object ID within the specified space. The response includes not only basic metadata (ID, name, icon, type) but also the complete set of blocks (which may include text, files, and relations) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view. +// @Tags objects +// @Produce json +// @Param space_id path string true "Space ID" +// @Param object_id path string true "Object ID" +// @Success 200 {object} ObjectResponse "The requested object" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Resource not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/objects/{object_id} [get] func GetObjectHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -81,19 +83,20 @@ func GetObjectHandler(s *ObjectService) gin.HandlerFunc { // DeleteObjectHandler deletes an object in a space // -// @Summary Delete object -// @Tags objects -// @Produce json -// @Param space_id path string true "Space ID" -// @Param object_id path string true "Object ID" -// @Success 200 {object} ObjectResponse "The deleted object" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 403 {object} util.ForbiddenError "Forbidden" -// @Failure 404 {object} util.NotFoundError "Resource not found" -// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/objects/{object_id} [delete] +// @Summary Delete object +// @Description This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues. +// @Tags objects +// @Produce json +// @Param space_id path string true "Space ID" +// @Param object_id path string true "Object ID" +// @Success 200 {object} ObjectResponse "The deleted object" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 403 {object} util.ForbiddenError "Forbidden" +// @Failure 404 {object} util.NotFoundError "Resource not found" +// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/objects/{object_id} [delete] func DeleteObjectHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -118,19 +121,20 @@ func DeleteObjectHandler(s *ObjectService) gin.HandlerFunc { // CreateObjectHandler creates a new object in a space // -// @Summary Create object -// @Tags objects -// @Accept json -// @Produce json -// @Param space_id path string true "Space ID" -// @Param object body CreateObjectRequest true "Object to create" -// @Success 200 {object} ObjectResponse "The created object" -// @Failure 400 {object} util.ValidationError "Bad request" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/objects [post] +// @Summary Create object +// @Description Creates a new object in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include key details such as the object name, icon, description, body content (which may support Markdown), source URL (required for bookmark objects), template identifier, and the unique key for the object type. Post-creation, additional operations (like setting featured relations or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions. +// @Tags objects +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param object body CreateObjectRequest true "Object to create" +// @Success 200 {object} ObjectResponse "The created object" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/objects [post] func CreateObjectHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -164,17 +168,18 @@ func CreateObjectHandler(s *ObjectService) gin.HandlerFunc { // GetTypesHandler retrieves a list of types in a space // -// @Summary List types -// @Tags types -// @Produce json -// @Param space_id path string true "Space ID" -// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) -// @Param limit query int false "The number of items to return" default(100) maximum(1000) -// @Success 200 {object} pagination.PaginatedResponse[Type] "List of types" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/types [get] +// @Summary List types +// @Description This endpoint retrieves a paginated list of object types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, unique key, display name, icon, and a recommended layout. Clients use this information when offering choices for object creation or for filtering objects by type. +// @Tags types +// @Produce json +// @Param space_id path string true "Space ID" +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" default(100) maximum(1000) +// @Success 200 {object} pagination.PaginatedResponse[Type] "List of types" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/types [get] func GetTypesHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -198,17 +203,18 @@ func GetTypesHandler(s *ObjectService) gin.HandlerFunc { // GetTypeHandler retrieves a type in a space // -// @Summary Get type -// @Tags types -// @Produce json -// @Param space_id path string true "Space ID" -// @Param type_id path string true "Type ID" -// @Success 200 {object} TypeResponse "The requested type" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Resource not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/types/{type_id} [get] +// @Summary Get type +// @Description Fetches detailed information about one specific object type by its ID. This includes the type’s unique key, name, icon, and recommended layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints). +// @Tags types +// @Produce json +// @Param space_id path string true "Space ID" +// @Param type_id path string true "Type ID" +// @Success 200 {object} TypeResponse "The requested type" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Resource not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/types/{type_id} [get] func GetTypeHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -232,18 +238,19 @@ func GetTypeHandler(s *ObjectService) gin.HandlerFunc { // GetTemplatesHandler retrieves a list of templates for a type in a space // -// @Summary List templates -// @Tags types -// @Produce json -// @Param space_id path string true "Space ID" -// @Param type_id path string true "Type ID" -// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) -// @Param limit query int false "The number of items to return" default(100) maximum(1000) -// @Success 200 {object} pagination.PaginatedResponse[Template] "List of templates" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/types/{type_id}/templates [get] +// @Summary List templates +// @Description This endpoint returns a paginated list of templates that are associated with a specific object type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects. +// @Tags types +// @Produce json +// @Param space_id path string true "Space ID" +// @Param type_id path string true "Type ID" +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" default(100) maximum(1000) +// @Success 200 {object} pagination.PaginatedResponse[Template] "List of templates" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/types/{type_id}/templates [get] func GetTemplatesHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -271,18 +278,19 @@ func GetTemplatesHandler(s *ObjectService) gin.HandlerFunc { // GetTemplateHandler retrieves a template for a type in a space // -// @Summary Get template -// @Tags types -// @Produce json -// @Param space_id path string true "Space ID" -// @Param type_id path string true "Type ID" -// @Param template_id path string true "Template ID" -// @Success 200 {object} TemplateResponse "The requested template" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Resource not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/types/{type_id}/templates/{template_id} [get] +// @Summary Get template +// @Description Fetches full details for one template associated with a particular object type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields. +// @Tags types +// @Produce json +// @Param space_id path string true "Space ID" +// @Param type_id path string true "Type ID" +// @Param template_id path string true "Template ID" +// @Success 200 {object} TemplateResponse "The requested template" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Resource not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/types/{type_id}/templates/{template_id} [get] func GetTemplateHandler(s *ObjectService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/internal/search/handler.go b/core/api/internal/search/handler.go index 57bbe33182..9113b30e2a 100644 --- a/core/api/internal/search/handler.go +++ b/core/api/internal/search/handler.go @@ -11,18 +11,19 @@ import ( // GlobalSearchHandler searches and retrieves objects across all spaces // -// @Summary Search objects across all spaces -// @Tags search -// @Accept json -// @Produce json -// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) -// @Param limit query int false "The number of items to return" default(100) maximum(1000) -// @Param request body SearchRequest true "Search parameters" -// @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /search [post] +// @Summary Search objects across all spaces +// @Description This endpoint executes a global search over every space the user has access to. It accepts pagination parameters (offset and limit) and a JSON body containing search criteria. The criteria include a search query string, an optional list of object types, and sort options (e.g. ascending/descending by creation, modification, or last opened dates). Internally, the endpoint aggregates results from each space, merges and sorts them (after last modified date by default), and returns a unified, paginated list of objects that match the search parameters. +// @Tags search +// @Accept json +// @Produce json +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" default(100) maximum(1000) +// @Param request body SearchRequest true "Search parameters" +// @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /search [post] func GlobalSearchHandler(s *SearchService) gin.HandlerFunc { return func(c *gin.Context) { offset := c.GetInt("offset") @@ -52,19 +53,20 @@ func GlobalSearchHandler(s *SearchService) gin.HandlerFunc { // SearchHandler searches and retrieves objects within a space // -// @Summary Search objects within a space -// @Tags search -// @Accept json -// @Produce json -// @Param space_id path string true "Space ID" -// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) -// @Param limit query int false "The number of items to return" default(100) maximum(1000) -// @Param request body SearchRequest true "Search parameters" -// @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/search [post] +// @Summary Search objects within a space +// @Description This endpoint performs a focused search within a single space (specified by the space_id path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search query, object types, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results. +// @Tags search +// @Accept json +// @Produce json +// @Param space_id path string true "Space ID" +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" default(100) maximum(1000) +// @Param request body SearchRequest true "Search parameters" +// @Success 200 {object} pagination.PaginatedResponse[object.Object] "List of objects" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/search [post] func SearchHandler(s *SearchService) gin.HandlerFunc { return func(c *gin.Context) { spaceID := c.Param("space_id") diff --git a/core/api/internal/space/handler.go b/core/api/internal/space/handler.go index 8c67c671b5..e52dcb2f62 100644 --- a/core/api/internal/space/handler.go +++ b/core/api/internal/space/handler.go @@ -11,16 +11,17 @@ import ( // GetSpacesHandler retrieves a list of spaces // -// @Summary List spaces -// @Tags spaces -// @Produce json -// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) -// @Param limit query int false "The number of items to return" default(100) maximum(1000) -// @Success 200 {object} pagination.PaginatedResponse[Space] "List of spaces" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces [get] +// @Summary List spaces +// @Description Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces. +// @Tags spaces +// @Produce json +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" default(100) maximum(1000) +// @Success 200 {object} pagination.PaginatedResponse[Space] "List of spaces" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces [get] func GetSpacesHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { offset := c.GetInt("offset") @@ -44,16 +45,17 @@ func GetSpacesHandler(s *SpaceService) gin.HandlerFunc { // GetSpaceHandler retrieves a space // -// @Summary Get space -// @Tags spaces -// @Produce json -// @Param space_id path string true "Space ID" -// @Success 200 {object} SpaceResponse "Space" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Space not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id} [get] +// @Summary Get space +// @Description Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings. +// @Tags spaces +// @Produce json +// @Param space_id path string true "Space ID" +// @Success 200 {object} SpaceResponse "Space" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Space not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id} [get] func GetSpaceHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -76,18 +78,19 @@ func GetSpaceHandler(s *SpaceService) gin.HandlerFunc { // CreateSpaceHandler creates a new space // -// @Summary Create space -// @Tags spaces -// @Accept json -// @Produce json -// @Param name body CreateSpaceRequest true "Space to create" -// @Success 200 {object} SpaceResponse "Space created successfully" -// @Failure 400 {object} util.ValidationError "Bad request" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces [post] +// @Summary Create space +// @Description Creates a new workspace (or space) based on a supplied name in the JSON request body. The endpoint is subject to rate limiting and automatically applies default configurations such as generating a random icon and initializing the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new space. +// @Tags spaces +// @Accept json +// @Produce json +// @Param name body CreateSpaceRequest true "Space to create" +// @Success 200 {object} SpaceResponse "Space created successfully" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 423 {object} util.RateLimitError "Rate limit exceeded" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces [post] func CreateSpaceHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { nameRequest := CreateSpaceRequest{} @@ -114,17 +117,18 @@ func CreateSpaceHandler(s *SpaceService) gin.HandlerFunc { // GetMembersHandler retrieves a list of members in a space // -// @Summary List members -// @Tags spaces -// @Produce json -// @Param space_id path string true "Space ID" -// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) -// @Param limit query int false "The number of items to return" default(100) maximum(1000) -// @Success 200 {object} pagination.PaginatedResponse[Member] "List of members" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/members [get] +// @Summary List members +// @Description Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which may be derived from an emoji or image), network identity, global name, and role (e.g. Reader, Writer, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights. +// @Tags spaces +// @Produce json +// @Param space_id path string true "Space ID" +// @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) +// @Param limit query int false "The number of items to return" default(100) maximum(1000) +// @Success 200 {object} pagination.PaginatedResponse[Member] "List of members" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/members [get] func GetMembersHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -148,17 +152,18 @@ func GetMembersHandler(s *SpaceService) gin.HandlerFunc { // GetMemberHandler retrieves a member in a space // -// @Summary Get member -// @Tags spaces -// @Produce json -// @Param space_id path string true "Space ID" -// @Param member_id path string true "Member ID" -// @Success 200 {object} MemberResponse "Member" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Member not found" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Security bearerauth -// @Router /spaces/{space_id}/members/{member_id} [get] +// @Summary Get member +// @Description Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global name, and role. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments. +// @Tags spaces +// @Produce json +// @Param space_id path string true "Space ID" +// @Param member_id path string true "Member ID" +// @Success 200 {object} MemberResponse "Member" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Member not found" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Security bearerauth +// @Router /spaces/{space_id}/members/{member_id} [get] func GetMemberHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") From 8935a5bb112724806115a94ca811e9adfaaa9e79 Mon Sep 17 00:00:00 2001 From: Jannis Metrikat <120120832+jmetrikat@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:34:06 +0100 Subject: [PATCH 31/31] GO-4459: Set metadata header with API version --- core/api/server/middleware.go | 8 ++++++++ core/api/server/router.go | 1 + 2 files changed, 9 insertions(+) diff --git a/core/api/server/middleware.go b/core/api/server/middleware.go index 1313127f80..2317c935f0 100644 --- a/core/api/server/middleware.go +++ b/core/api/server/middleware.go @@ -95,3 +95,11 @@ func (s *Server) ensureAccountInfo(accountService account.Service) gin.HandlerFu c.Next() } } + +// ensureMetadataHeader is a middleware that ensures the metadata header is set. +func (s *Server) ensureMetadataHeader() gin.HandlerFunc { + return func(c *gin.Context) { + c.Writer.Header().Set("X-API-Version", "0.0.2") + c.Next() + } +} diff --git a/core/api/server/router.go b/core/api/server/router.go index f3397da1c0..67237092c8 100644 --- a/core/api/server/router.go +++ b/core/api/server/router.go @@ -37,6 +37,7 @@ func (s *Server) NewRouter(accountService account.Service, mw service.ClientComm router := gin.New() router.Use(gin.Recovery()) + router.Use(s.ensureMetadataHeader()) if debug { router.Use(gin.Logger())