Skip to content

PerfectTemplate 4.0.0

Latest

Choose a tag to compare

@taplin taplin released this 15 Oct 19:52
7b3a5c3

PerfectTemplate 4.0.0 replaces the 2017 single-file starter (3.0.0) with a reference app for the Swift 6 Perfect stack: a small "Posts" JSON API and browser UI built on Perfect-NIO, Perfect-CRUD, Perfect-MySQL and Perfect-Logger, all pinned to released versions. Copy it as the starting point for a new service. (#25)

Requirements

  • Swift 6.2 or later (swift-tools-version: 6.2), macOS 12 or later, or Linux. CI covers Swift 6.2 and 6.4 on Ubuntu 24.04 and Xcode 26.0.1 and 26.6 on macOS, in debug and release, with warnings as errors.
  • The MySQL client library: mysql-client from Homebrew on macOS, libmysqlclient-dev on Debian/Ubuntu.
  • A MySQL 5.7.8+ or MariaDB 10.1+ server. Tested with MySQL 8.4 and MariaDB 11.8.
  • Dependencies: Perfect-NIO 0.1.0, Perfect-CRUD 3.1.0, Perfect-MySQL 4.0.0, Perfect-Logger 4.0.0, swift-nio 2.65.0+. Package.resolved is committed.

What's in it

  • JSON API: GET /api/health, GET|POST /api/posts, GET|PUT|DELETE /api/posts/:id. UUID ids, ISO 8601 createdAt, newest first.
  • Web UI: / and /posts (create, edit, delete), plus /static/*. GET and HEAD.
  • Configuration from the environment: PORT (9191), DB_HOST (127.0.0.1), DB_PORT (13306), DB_NAME, DB_USER, DB_PASS, WEBROOT, LOG_FILE, LOG_LEVEL. The defaults match the README's container quick start, so a bare swift run never connects to a MySQL on 3306. A bad port exits with a clear message.
  • Schema: the table is created on the first successful connection, so the server can start before MySQL is up.
  • Logging through Perfect-Logger to the console and a file, with CRUD's SQL at debug level.
  • CI and a smoke test: Scripts/smoke-test.sh checks the pages, health, a full create/list/get/update/delete round trip and the error cases; --no-db checks the outage behaviour.

Behaviour worth knowing

  • Database work runs on its own 16-thread pool, not on Swift's cooperative thread pool. A slow or unreachable database can't stop the server answering health checks and pages.
  • Timeouts: connect 5 s; client read and write 30 s; server-side lock waits and statement time 20 s, so MySQL gives up before the client does. A request that hits them answers 503 "Database busy." and, because each statement autocommits, nothing is written. On MariaDB the statement limit applies to every statement; on MySQL only to SELECTs.
  • Outages: a failed connect answers 503 "Database unavailable.", and for 2 s afterwards requests fail fast instead of queuing for another connect.
  • Validation: POST and PUT need Content-Type: application/json (415). Titles are 1–200 characters on one line, without control, line-separator or bidi-override characters, and at most 2,000 code points; bodies are at most 20,000 characters and 100,000 code points. Request bodies are capped at 256 KiB (413). PUT changes only the fields sent.
  • Errors map to 400, 404, 413, 415, 503 or a generic 500; internal error text only goes to the log.
  • The server listens on all interfaces (Perfect-NIO's default).

Known limitations

  • "Database busy" is recognised from the MySQL error text, because Perfect-MySQL 4.0.0's errors don't carry the error number. A server set to non-English messages answers 500 for those timeouts instead of 503.
  • A table dropped while the app runs needs an app restart.
  • A SELECT that legitimately takes more than 20 s answers 503.
  • One connection per request; for a busy service, look at CRUD's connection pool (see the README).

Upgrading from 3.0.0

There is no upgrade path: 4.0.0 is a new app on a new stack. The old Perfect 3 starter is on the legacy branch. README.zh_CN.md was removed rather than left out of date.