← Todos los tutoriales
web-app 10 min

Todo Junto

Construyamos un gestor de marcadores — añade URLs con un título y véalos listados. Este tutorial une todo de esta pista: configuración del servidor, lecturas y escrituras en base de datos, formularios, componentes y listado de registros. Suficientemente pequeño para entender completamente, suficientemente real para ser útil.

El archivo servidor declara plugins, importa helpers y lista todas las rutas:

plugins:\n    frame.server\n    frame.data\n\nimport:\n    "helpers.cln"\n\nendpoints server:\n    GET "/" :\n        return http.respond(200, "text/html", render_home())\n\n    GET "/add" :\n        return http.respond(200, "text/html", render_add_form())\n\n    POST "/add" :\n        string title = req.body("title")\n        string url = req.body("url")\n        if title == "" or url == ""\n            return http.respond(400, "text/html", render_add_form())\n        string params = "[\\"" + title + "\\", \\"" + url + "\\"]"\n        db.query("INSERT INTO bookmarks (title, url) VALUES (?, ?)", params)\n        return http.respond(200, "text/html", render_home())
GET  /     → bookmarks list page\nGET  /add  → add bookmark form\nPOST /add  → save and show updated list

El archivo servidor es liviano — solo rutas. Tres rutas cubren el ciclo completo: listar, mostrar formulario, guardar. Valida antes de insertar y devuelve el formulario con 400 en caso de error. Delega el renderizado a helpers.cln para mantener el archivo servidor legible.

La función render_home() en helpers.cln obtiene y muestra todos los marcadores:

functions:\n    string bookmark_item(string title, string url)\n        html:\n            
  • \n {title}\n
  • \n\n string render_home()\n string cnt_res = db.query("SELECT CAST(COUNT(*) AS CHAR) as cnt FROM bookmarks", "[]")\n integer count = json.get(cnt_res, "data.rows.0.cnt").toInteger()\n string bm_res = db.query("SELECT title, url FROM bookmarks ORDER BY id DESC", "[]")\n string items = ""\n iterate i in 0 to count - 1\n string t = json.get(bm_res, "data.rows." + i.toString() + ".title")\n string u = json.get(bm_res, "data.rows." + i.toString() + ".url")\n items = items + bookmark_item(t, u)\n html:\n \n

    My Bookmarks

    \n + Add Bookmark\n
      {!items}
    \n
    Renders a page with all saved bookmarks as clickable links

    render_home() aplica el patrón de listado del tutorial anterior: contar, obtener, iterar, renderizar. El componente bookmark_item se llama una vez por fila. Separación de responsabilidades: server.cln maneja el enrutamiento, helpers.cln maneja el renderizado.

    Resumen rápido

    • Mantén server.cln ligero — solo rutas, delega el renderizado a helpers.cln
    • Tres rutas cubren una característica completa: listar, mostrar formulario, guardar
    • Valida la entrada del formulario antes de insertar — devuelve el formulario con 400 en caso de error
    • Los mismos patrones se repiten en cada aplicación: consultar, contar, iterar, renderizar
    ¡Copiado!