---
title: "Sticky Notes"
description: "Sticky-notes REST API where titles and previews are computed columns, served with FastAPI"
url: "https://www.pixeltable.com/recipes/sticky-notes"
source: "https://github.com/pierrebrunelle/pixeltable-sticky-notes"
---

# Sticky Notes

Sticky-notes REST API where titles and previews are computed columns, served with FastAPI

One `app.py` with 1 table, 2 computed columns, 5 HTTP routes. Needs `pixeltable[serve]>=0.7.14`.

## Tables

### notes (table)

| Column | Kind | Type or expression |
| --- | --- | --- |
| id | primary key | `pxtf.uuid.uuid7()` |
| title | stored | String |
| body | stored | String |
| tag | stored | String (optional) |
| title_upper | computed on insert | `pxtf.string.upper(title)` |
| blurb | computed on insert | `blurb(body)` |

## Routes (service `notes_api`)

- `POST /notes`: inserts into `notes` (takes title, body, tag; returns id, title_upper, blurb)
- `POST /notes/update`: updates `notes` (takes title; returns id, title_upper)
- `POST /notes/delete`: deletes from `notes`
- `POST /titles`: computes `notes` columns without storing (takes title; returns title_upper)
- `GET /notes/by-tag`: runs the query `notes_by_tag` (takes tag)

## Run it locally

```sh
git clone https://github.com/pierrebrunelle/pixeltable-sticky-notes
cd pixeltable-sticky-notes
uv sync
uv run pxt schema update app.py notes
uv run python seed.py notes
uv run pxt service run app.py notes --port 8000
```

## Run it on Pixeltable Cloud

```sh
uv run pxt new    # a free database, no account
# put the pxt:// address it prints in pixeltable.toml
uv run pxt db update pxt://<org>:main -f
uv run pxt schema update app.py pxt://<org>:main -f
uv run pxt service update app.py pxt://<org>:main -f
```

## app.py

At commit `e923366f` (https://github.com/pierrebrunelle/pixeltable-sticky-notes/blob/e923366fd123461ee067a3ed664c712dc26343b1/app.py):

```python
"""Sticky Notes API built with Pixeltable.

    pxt schema update app.py notes
    pxt service run app.py notes
"""
import pixeltable as pxt
import pixeltable.functions as pxtf
from pixeltable.serving import FastAPIRouter

from udfs import blurb

# ---- tables ----
TableModel = pxt.model_base()


class Notes(TableModel, name='notes'):
    id = pxt.Column(value=pxtf.uuid.uuid7(), primary_key=True)
    title: pxt.String
    body: pxt.String
    tag: pxt.String | None

    title_upper = pxtf.string.upper(title)   # built-in string function
    blurb = blurb(body)                       # our UDF from udfs.py


# ---- queries ----
@pxt.query
def notes_by_tag(tag: str):
    """Notes with a given tag, newest first (UUIDv7 ids sort by creation time)."""
    return Notes.where(Notes.tag == tag).select(Notes.id, Notes.title, Notes.blurb).order_by(Notes.id, asc=False)


# ---- routes ----
notes_api = FastAPIRouter(name='notes_api')
notes_api.add_insert_route(Notes, path='/notes', inputs=[Notes.title, Notes.body, Notes.tag],
                           outputs=[Notes.id, Notes.title_upper, Notes.blurb])
notes_api.add_update_route(Notes, path='/notes/update', inputs=[Notes.title], outputs=[Notes.id, Notes.title_upper])
notes_api.add_delete_route(Notes, path='/notes/delete')
notes_api.add_compute_route(Notes, path='/titles', inputs=[Notes.title], outputs=[Notes.title_upper])
notes_api.add_query_route(path='/notes/by-tag', query=notes_by_tag, method='get')
```
