GET /api
Everything you can ask for.
Anything on this site you can also get as data, if you'd rather pull it into a program than read it. This is the list of what you can ask for, what you get back, and which page shows the same thing in words.Ten endpoints, nine reads and one write. Each one is also a page here, built from the same data, so the page and the answer can't disagree. Below is what each one takes and what it gives back.
Every answer comes with the page it came from, so you can always go check it against what's written there.Add ?fields=a,b to any GET if you only want part of the record; page comes back either way. If something's wrong it says so: a bad parameter is a 400 that lists what's allowed, an id that doesn't exist is a 404 with a hint, the wrong method is a 405. A 200 gets cached for five minutes, nothing else does.
GET /api/dylan
Home
Who this is: role, employer, the one-sentence summary in either register, location, links.
- view
- Which register the summary is written in. The site has two; the pages show both.plain · engineer
- fields
- Comma-separated keys to return instead of the whole record. `page` always comes back.
- source
- src/lib/site.ts
GET /api/work
Work
What I built at my job: the ERP and the AI coding setup around it. Their parts are in each one's record.
- fields
- Comma-separated keys to return instead of the whole record. `page` always comes back.
- source
- src/content/projects/*
GET /api/work/{id}
One piece of work
One piece of work in full: the contract (problem, what was unique, what I learned), the numbers, the parts.
- id
- An id from GET /api/work, or a part of one like internal-erp/repricing.
- fields
- Comma-separated keys to return instead of the whole record. `page` always comes back.
- source
- src/content/projects/{id}
GET /api/projects
Projects
Everything else I built: tools, games and a course project, newest and most important first.
- category
- Filter to one shelf: tool, game or course. What the thing is, not what it was built with.tool · game · course
- fields
- Comma-separated keys to return instead of the whole record. `page` always comes back.
- source
- src/content/projects/*
GET /api/projects/{id}
One project
One project in full: the contract (problem, what was unique, what I learned), the numbers.
- id
- An id from GET /api/projects.
- fields
- Comma-separated keys to return instead of the whole record. `page` always comes back.
- source
- src/content/projects/{id}
GET /api/experience
About
The path here — the stops, the jobs, education and certifications.
- since
- Only jobs that started in this year or later.2021 · 2022 · 2025
- fields
- Comma-separated keys to return instead of the whole record. `page` always comes back.
- source
- src/lib/site.ts
GET /api/resume
Resume
The one-page résumé: summary, experience with bullets, projects, skills, education. The same facts as the PDF.
- format
- json returns the record; html and pdf return the record with `page` pointing at that version.json · html · pdf
- fields
- Comma-separated keys to return instead of the whole record. `page` always comes back.
- source
- src/lib/site.ts
GET /api/away-from-work
Away from work
What I do when I'm not at a keyboard, and the first thing I ever shipped. It still runs.
- playable
- When true, `page` is the playable game instead of its write-up.
- fields
- Comma-separated keys to return instead of the whole record. `page` always comes back.
- source
- src/lib/site.ts · src/content/projects/galaxy-defense
POST /api/contact
Contact
Send a message. Until mail delivery is configured the route answers 503 with a mailto link, and the console opens it.
- from
- Your email, so I can reply.
- message
- The message. Ten characters or more.
- source
- src/pages/api/contact.ts
GET /api
API reference · this page
This list: every endpoint, what it takes, where the answer comes from and which page it's on.
- source
- src/lib/endpoints.ts
Request
curl "https://dylansg.com/api"
Response200 OK · 6.1 KB
{ "name": "dylansg.com", "description": "Read-only, the same facts the site shows. Every record has `page`, the address of the page it came from.", "endpoints": [ { "method": "GET", "path": "/api/dylan", "description": "Who this is: role, employer, the one-sentence summary in either register, location, links.", "params": [ { "name": "view", "description": "Which register the summary is written in. The site has two; the pages show both.", "one_of": [ "plain", "engineer" ] }, { "name": "fields", "description": "Comma-separated keys to return instead of the whole record. `page` always comes back." } ], "source": "src/lib/site.ts", "page": "https://dylansg.com/" }, { "method": "GET", "path": "/api/work", "description": "What I built at my job: the ERP and the AI coding setup around it. Their parts are in each one's record.", "params": [ { "name": "fields", "description": "Comma-separated keys to return instead of the whole record. `page` always comes back." } ], "source": "src/content/projects/*", "page": "https://dylansg.com/work" }, { "method": "GET", "path": "/api/work/{id}", "description": "One piece of work in full: the contract (problem, what was unique, what I learned), the numbers, the parts.", "params": [ { "name": "id", "description": "An id from GET /api/work, or a part of one like internal-erp/repricing.", "one_of": [] }, { "name": "fields", "description": "Comma-separated keys to return instead of the whole record. `page` always comes back." } ], "source": "src/content/projects/{id}", "page": "https://dylansg.com/work/internal-erp" }, { "method": "GET", "path": "/api/projects", "description": "Everything else I built: tools, games and a course project, newest and most important first.", "params": [ { "name": "category", "description": "Filter to one shelf: tool, game or course. What the thing is, not what it was built with.", "one_of": [ "tool", "game", "course" ] }, { "name": "fields", "description": "Comma-separated keys to return instead of the whole record. `page` always comes back." } ], "source": "src/content/projects/*", "page": "https://dylansg.com/projects" }, { "method": "GET", "path": "/api/projects/{id}", "description": "One project in full: the contract (problem, what was unique, what I learned), the numbers.", "params": [ { "name": "id", "description": "An id from GET /api/projects.", "one_of": [] }, { "name": "fields", "description": "Comma-separated keys to return instead of the whole record. `page` always comes back." } ], "source": "src/content/projects/{id}", "page": "https://dylansg.com/projects/receipt-splitter" }, { "method": "GET", "path": "/api/experience", "description": "The path here — the stops, the jobs, education and certifications.", "params": [ { "name": "since", "description": "Only jobs that started in this year or later.", "one_of": [ "2021", "2022", "2025" ] }, { "name": "fields", "description": "Comma-separated keys to return instead of the whole record. `page` always comes back." } ], "source": "src/lib/site.ts", "page": "https://dylansg.com/about" }, { "method": "GET", "path": "/api/resume", "description": "The one-page résumé: summary, experience with bullets, projects, skills, education. The same facts as the PDF.", "params": [ { "name": "format", "description": "json returns the record; html and pdf return the record with `page` pointing at that version.", "one_of": [ "json", "html", "pdf" ] }, { "name": "fields", "description": "Comma-separated keys to return instead of the whole record. `page` always comes back." } ], "source": "src/lib/site.ts", "page": "https://dylansg.com/resume" }, { "method": "GET", "path": "/api/away-from-work", "description": "What I do when I'm not at a keyboard, and the first thing I ever shipped. It still runs.", "params": [ { "name": "playable", "description": "When true, `page` is the playable game instead of its write-up." }, { "name": "fields", "description": "Comma-separated keys to return instead of the whole record. `page` always comes back." } ], "source": "src/lib/site.ts · src/content/projects/galaxy-defense", "page": "https://dylansg.com/#away" }, { "method": "POST", "path": "/api/contact", "description": "Send a message. Until mail delivery is configured the route answers 503 with a mailto link, and the console opens it.", "params": [ { "name": "from", "description": "Your email, so I can reply." }, { "name": "message", "description": "The message. Ten characters or more." } ], "source": "src/pages/api/contact.ts", "page": "https://dylansg.com/contact" }, { "method": "GET", "path": "/api", "description": "This list: every endpoint, what it takes, where the answer comes from and which page it's on.", "params": [], "source": "src/lib/endpoints.ts", "page": "https://dylansg.com/reference" } ], "fields": "Add ?fields=a,b to any GET to get only those keys; `page` always comes back.", "page": "https://dylansg.com/reference" }
Live: this is the real index, the same list every console on the site is built from. Send runs it again.