feat: add description to functions, sites, variables, keys, webhooks and databases by Meldiron · Pull Request #14355 · appwrite/appwrite · GitHub
Skip to content

feat: add description to functions, sites, variables, keys, webhooks and databases - #14355

Merged
Meldiron merged 6 commits into
feat/description-schemafrom
feat/function-description
Oct 14, 2026
Merged

Meldiron merged 6 commits into
feat/description-schemafrom
feat/function-description

Conversation

@Meldiron

@Meldiron Meldiron commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Stacked on #14471, which adds the description attributes to the collection schema and the V25 upgrade steps. Merge that one first. This PR is the API side: params, response models, search and tests.

Adds an optional description to functions, sites, variables, API keys, webhooks, databases, tables/collections, columns/attributes, indexes, storage buckets and messaging topics. It follows how WAF rules handle descriptions on Cloud (appwrite-labs/cloud, Modules/WAF/Http/Rules/*): same param name, limit, validator, update semantics and wording.

API

Every resource takes the same description param:

Create Update
Validator Text(1024, 0), optional Nullable(Text(1024, 0)), optional
Omitted stored as '' stored value is kept
'' stored as '' clears it

The field is returned on every matching response model. Docs text is "Optional description for the {resource}.", as on Cloud.

Resource Endpoints
Functions POST /v1/functions, PUT /v1/functions/:functionId
Sites POST /v1/sites, PUT /v1/sites/:siteId
Variables create/update for function, site and project variables
API keys create/update on the project keys and organization project keys routes
Webhooks POST /v1/webhooks, PUT /v1/webhooks/:webhookId
Databases create/update on Databases, TablesDB, DocumentsDB and VectorsDB
Tables / collections create/update on all four database APIs
Columns / attributes create/update for all 18 types, on TablesDB columns and legacy attributes
Indexes create on all four database APIs (indexes have no update endpoint)
Buckets POST /v1/storage/buckets, PUT /v1/storage/buckets/:bucketId
Topics POST /v1/messaging/topics, PATCH /v1/messaging/topics/:topicId

Behaviour notes:

  • description is the last param on each endpoint. Existing params keep their positions, so SDK calls that pass arguments positionally still work. Subclasses that inherit an action (TablesDB, DocumentsDB and VectorsDB on top of the legacy Databases actions) declare it in the same position. A script checked the 109 database, compute, key, variable and webhook endpoints that take description for this. The 4 bucket and topic endpoints were checked by hand.
  • Inline column and index definitions on table/collection create also accept description. The Attributes and Indexes validators check it with the same Text(1024, 0).
  • Functions, sites, databases, tables/collections, buckets and topics add the description to their search index, so ?search= on those lists matches it. Topics already had description in their topicSearch filter, so they only needed the column. Bucket update now rewrites search too. Before, it never did, so a renamed bucket was only found by its old name. Variables, keys and webhooks have no list search, so their search value is unchanged. Description is not a filterable query attribute anywhere, which matches WAF rules.
  • Changing a description does not set a function's or site's live to false. A description-only update on a variable also skips that step. Before, any project variable update set live: false on every function and site in the project.
  • A variable update with only description set returns 200. Before, an update with no key, value or secret returned 400.
  • The other side of a two-way relationship is created with an empty description. The description sent belongs to the column it was sent for.

Storage

The description attributes (size 1024, default '') and the V25 upgrade steps moved to #14471. Its description lists the collections and the MariaDB row widths.

Not in this PR

  • Cloud columns. appwrite-labs/cloud#6485 adds them through patch tasks, and has to run before this ships there. It covers buckets and topics in both the platform and project databases.
  • Console UI to show and edit descriptions.
  • Carrying description through utopia-php/migration exports and the CLI's appwrite.config.json.
  • An update endpoint for indexes. Index descriptions can only be set on create.
  • Projects already have a description with a different limit and wording (Text(256), "Project description. Max length: 256 chars."). This PR leaves it unchanged.

SDK usage

await tablesDB.createTable({
    databaseId: 'shop',
    tableId: sdk.ID.unique(),
    name: 'Orders',
    description: 'One row per checkout, written by the checkout function.',
});

await tablesDB.createVarcharColumn({
    databaseId: 'shop',
    tableId: '<TABLE_ID>',
    key: 'status',
    size: 32,
    required: true,
    description: 'pending, paid or refunded.',
});

// Omitting description keeps the stored one
await functions.updateVariable({
    functionId: '<FUNCTION_ID>',
    variableId: '<VARIABLE_ID>',
    value: '<NEW_VALUE>',
});

Test Plan

CI on this PR ran the E2E lanes on PostgreSQL and passed: Databases (1,295 tests), TablesDB (526), Project (977), Sites (65), Organization (102), Webhooks (139), Functions (88). MariaDB, MongoDB and shared-tables lanes did not run. The Storage and Messaging tests for buckets and topics were added after that run and have not run yet. The functions tests also ran locally against Postgres (4 tests, 103 assertions); the rest has not run locally.

E2E:

  • Databases/DatabasesBase (Legacy, TablesDB and DocumentsDB):
    • testUpdateDatabaseDescription and testUpdateCollectionDescription: set on create, '' default, kept on update without it, cleared with '', found by search, 1025 chars returns 400 general_argument_invalid.
    • testUpdateAttributeDescription: creates one column of every type with a description, then updates each through its own type endpoint. This catches a mis-wired param in any of the 72 column/attribute files. Spatial types and relationships run where the adapter supports them.
    • testCreateCollectionInlineDescription: inline column and index definitions.
    • testCreateIndexDescription: index create.
  • Databases/VectorsDB/DatabasesBase: database, collection and index descriptions.
  • Sites (SitesCustomServerTest): the create/get/list/update tests are extended, and testUpdateVariableDescription is new.
  • Variables: function, site and project scopes. Each checks a description-only update (200), that a value update keeps the description, and live staying true on a description-only update but going false on a value update.
  • Keys: project keys (Project/KeysBase) and organization project keys (Organization/KeysBase).
  • Webhooks: the description survives a secret rotation and is returned on list.
  • Functions: create/get/list/update, from the first commit.
  • Buckets (StorageCustomServerTest::testUpdateBucketDescription): same cases as databases. It also checks that search matches the new description after an update and no longer matches the old one.
  • Topics (MessagingBase::testUpdateTopicDescription): same cases as databases, on the PATCH update.

Unit tests for the inline definition validators (AttributesTest::testDescription and the new IndexesTest) pass on the host.

Static checks:

  • PHPStan and Pint are clean on all changed files. Rector is clean on the tests. The bucket and topic changes passed Pint, but PHPStan and Rector have not run on them yet.
  • MariaDB row widths are listed above.
  • A script compared the description param position with the action signature each endpoint runs, including inherited ones. It checked all 109 endpoints that take description and found no mismatches.

Related PRs and Issues

Checklist

  • Have you read the Contributing Guidelines on issues?
  • If the PR includes a change to an API's metadata (desc, label, params, etc.), does it also include updated API specs and example docs?

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Security rules

No new WARNING or ERROR findings from security rules.

19 existing findings tracked in .semgrep/baseline.json
  • php.appwrite.guest-write-without-abuse-limit (12)
  • php.appwrite.secret-compare-timing (5)
  • php.appwrite.weak-secret-env-default (2)

Posted by Checks / Rules. Re-runs update this comment in place. Rule details and baseline: .semgrep/README.md.

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

✨ Benchmark results

Comparing main (before) → feat/function-description (after).

Metric Before After Change
🚀 Requests/sec 221.25 224.7 ⚪ +1.6%
⏱️ Latency P50 77.41 ms 76.45 ms ⚪ -1.2%
⏱️ Latency P95 180.51 ms 182.48 ms ⚪ +1.1%
Per-scenario breakdown & investigation details

Metrics below reflect the current branch (after). Δ P95 compares against the base.

Scenario P50 (ms) P95 (ms) Requests RPS Δ P95 (ms)
API total 76.45 182.48 13,851 224.7 +1.97
Account 150.69 284.17 729 12.08 -1.78
TablesDB 73.76 131.19 7,533 123.83 -2.71
Storage 70.35 151.47 3,645 62.22 -8.42
Functions 115.78 236.66 1,944 33.89 -10.09

Top API waits (after)

API request Max wait (ms)
account.name.update 419.77
account.prefs.update 371.91
functions.variables.update 365.48
functions.create 357.38
functions.delete 331.8

Meldiron and others added 3 commits October 12, 2026 12:23
Optional description on create and update, stored on the functions
collection (1024 chars, default '') and included in search. Mirrors
WAF rule descriptions on Cloud.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Same shape as functions: optional, up to 1024 chars, default '', kept on
update when omitted. Covers sites, function/site/project variables, API
keys, webhooks, databases, tables/collections, columns/attributes (every
type, legacy and TablesDB) and indexes, including inline column and index
definitions on table create. Searchable where the list endpoint supports
search. Description-only variable updates no longer mark functions or
sites for redeploy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bases

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Meldiron
Meldiron force-pushed the feat/function-description branch from 2f9057a to 6438d20 Compare October 12, 2026 10:50
@Meldiron Meldiron changed the title feat: add description to functions feat: add description to functions, sites, variables, keys, webhooks and databases Oct 12, 2026
Meldiron and others added 2 commits October 13, 2026 10:31
Main added a webhooks case to V25 for httpPass, which shadowed the
webhooks label in the keys case. Move the description step into it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bucket update now also rewrites search, which it never did, so a
renamed bucket was only found by its old name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Meldiron
Meldiron marked this pull request as ready for review October 13, 2026 08:48
@tenki-reviewer

tenki-reviewer Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Review complete. 🟡 1 medium

📍 Findings outside the diff (1) — 🟡 1 medium — defects on lines GitHub can't attach comments to

🟡 Medium — Topic description never indexed into search · Create.php:83 · unchanged line

// src/Appwrite/Platform/Modules/Messaging/Http/Topics/Create.php
83	        try {

Topics Create and Update now store description (src/Appwrite/Platform/Modules/Messaging/Http/Topics/Create.php:83), but neither builds the topic's search attribute, unlike every other resource in this PR (databases, collections, functions, sites, buckets) that folds the description into search. Since Topics/XList filters with Query::search('search', $search), topics can never be found by their description; the new e2e test testUpdateTopicDescription in tests/e2e/Services/Messaging/MessagingBase.php asserts exactly that and will fail.

🧹 Nitpicks (1) — 🟢 1 low
  • 🟢 Two-way relationship mirror drops description (Action.php:433) — Relationship/Create now forwards the new description field into createAttribute, and the primary attribute document stores it (src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Action.php:379), but the $twoWayAttribute mirror document omits the key.

The change threads an optional, length-capped description param through ~25 API resources' create/update endpoints and persists it into collection metadata, folding it into search where relevant. Response models gain the rule with a '' default so older SDKs round-trip safely.

Files Change
app/config/collections/*.php Adds a description string attribute (size 1024, default '') to the touched collection schemas.
src/Appwrite/Migration/* Adds V25 backfilling description via createAttributeFromCollection across project and console collections, plus the collections→databases remap in Migration.php.
src/Appwrite/Platform/Modules/Databases/Http/** Adds description params to database/collection/table/attribute/column/index create-update endpoints across Databases, TablesDB, DocumentsDB, and VectorsDB surfaces.
src/Appwrite/Platform/Modules/{Functions,Sites,Project,Organization,Messaging,Storage,Webhooks}/** Adds description params to functions, sites, variables, keys, buckets, topics, and webhooks endpoints; variable updates no longer flip live on description-only changes.
src/Appwrite/Utopia/{Database/Validator,Response/Model}/* Adds description rules to validators and 14 response models with safe defaults.
tests/** Adds e2e assertions for description (including 1025-char rejection) across service bases and unit tests for the validators.

Reviewed commit: 4527b30

@hansi-codes

hansi-codes Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

🟢 Tier S · Ready to merge

Adds optional descriptions to compute resources, variables, keys, webhooks, database resources, storage buckets, and messaging topics. The change extends collection schemas and the V25 migration, updates response models and relevant search fields, and adds API and validator coverage.

68 of 150 changed files were too large to include in full.

Verdict New comments Fixed Still open
💬 Commented 0 0 0

Note

Part of the diff was too large to review, so Hansi did not approve.

📂 Walkthrough · 7
File Change
app/config/collections/{common,databases,platform,projects,vectorsdb}.php Adds persisted description attributes to the affected collections and per-database metadata templates.
src/Appwrite/Migration/{Migration.php,Version/V25.php} Adds schema migration support for descriptions, including per-database metadata collections.
src/Appwrite/Platform/Modules/Databases/Http/** Adds description parameters and persistence across database APIs, including inline columns and indexes.
src/Appwrite/Platform/Modules/{Functions,Sites,Project,Organization,Storage,Messaging,Webhooks}/Http/** Adds description create/update handling for compute, variables, keys, buckets, topics, and webhooks.
src/Appwrite/Utopia/Database/Validator/{Attributes.php,Indexes.php} Validates descriptions in inline database definitions.
src/Appwrite/Utopia/Response/Model/*.php Exposes descriptions in affected resource response models.
tests/{e2e,unit}/** Adds description behavior coverage for APIs and inline-definition validators.
🔇 Filtered out · 1

Findings Hansi considered but did not post.

Finding Why
Reject null descriptions in inline definitions Verifier: Null is consistently treated as omission for these optional create fields. The standalone description parameters use optional=true and default='', and packages/http/src/Http.php:735–745 explicitly substitutes the default when an optional parameter is null and its validator rejects null. The inline builders likewise normalize null to '' (Collections/Create.php:340 and 417). Thus the isset checks match the actual HTTP contract rather than bypassing a requirement to reject null.

Merged main (33ee90d); no changes to this PR's code since 4527b30 · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Tier S · Looks good to merge. Summary

@Meldiron

Copy link
Copy Markdown
Contributor Author

The schema half of this PR moved to feat/description-schema so it can merge
first. Merging it here also brings in main; the only conflicts were the topic
`expiry` param rewording next to the new `description` param.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Meldiron
Meldiron changed the base branch from main to feat/description-schema October 14, 2026 10:57
imtia33 pushed a commit to imtia33/appwrite that referenced this pull request Oct 14, 2026
Adds an optional `description` string (size 1024, default '') to functions,
sites, variables, databases, attributes, indexes, keys, webhooks, buckets,
topics and the per-database metadata collection template, with the V25
upgrade steps that add it to existing installs.

Schema only: no endpoint reads or writes the attribute yet, and response
models do not expose it. The API side follows in appwrite#14355.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Meldiron
Meldiron merged commit a9a6e99 into feat/description-schema Oct 14, 2026
63 checks passed
HarshMN2345 added a commit that referenced this pull request Oct 16, 2026
…resh the SDK lock

Drops the explicit-null handling I had added on top of #14355. That 500 is not
specific to description: 211 optional Text params across main's create endpoints
share the shape (entrypoint and commands on Functions/Create.php, for two),
because Utopia skips validation for an explicit null and only falls back to the
declared default when the key is absent. Fixing it for description alone would
be inconsistent with the rest of the API, so it belongs in its own PR.

What remains on top of #14355 is only what main requires:

- tests/e2e/.../VectorsDB/DatabasesBase.php and the two validator unit tests
  used Database::INDEX_HNSW_* and the pre-enum attribute constants; main has
  moved to the IndexType/ColumnType enums, so they died resolving a constant
  before reaching their assertions.
- app/config/sdks/parameters.lock.json carried no description entries, so
  ParametersTest::testMethodsAreLocked failed on every touched method.
  Regenerated, not hand-patched: 222 entries gain "description", no method
  added, removed or reordered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
NancyWei123 pushed a commit to NancyWei123/appwrite that referenced this pull request Oct 16, 2026
The API params for resource descriptions were merged into
feat/description-schema by appwrite#14355 ten hours after appwrite#14471 had already
merged that branch's then-tip into main, so the params never reached
main. This merge brings them across.

51 files conflicted, 49 of them under the Databases module, because main
refactored the attribute/column endpoints after the branch was cut. Every
conflict is resolved by keeping main's structure and applying only the
branch's description addition on top:

  - Database::VAR_* -> ColumnType::*->value (main's enum migration)
  - getAdapter()->getMaxUIDLength() -> getMaxUidLength()
  - getAdapter()->get{Min,Max}DateTime() -> getAdapter()->limits()->{min,max}DateTime
  - new Spatial(Database::VAR_*) -> new Spatial(ColumnType::*->value)

tests/e2e/Services/Databases/DatabasesBase.php is rebuilt from main's
version plus the branch's five new description tests, ported to main's
enums and Id::unique() casing, because git had interleaved the branch's
new tests with three main-only tests added in the same region.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant