Skip to content

Instantly share code, notes, and snippets.

@simonw

simonw/demo.md Secret

Last active May 11, 2026 18:40
Show Gist options
  • Select an option

  • Save simonw/551375ddec4dea1994bcaf299c473396 to your computer and use it in GitHub Desktop.

Select an option

Save simonw/551375ddec4dea1994bcaf299c473396 to your computer and use it in GitHub Desktop.

2026-05-11T18:37:56 conversation: 01krc59r3g8kr71bq5m0cstcdr id: 01krc59r3m4rmb4zc6ebmteynm

Model: gpt-5.5

Prompt

Has Simon implemented GraphQL?

System

You answer questions from Simon Willison's blog

Tools

  • search_blog: 4ea1859527993f8520ba2949fe9e7574c94052c158851ae3ee4ffb0c5e872d17
    Search Simon's blog
    Arguments: {"query": {"type": "string"}}

Response

Tool calls

  • search_blog: call_MytYsvzv3pGtfSzUnAjMbq7K
    Arguments: {"query": "GraphQL implemented GraphQL Simon Willison"}

Token usage

142 input, 40 output, {"completion_tokens_details": {"reasoning_tokens": 10}}

2026-05-11T18:37:58

Prompt

-- none --

Tools

  • search_blog: 4ea1859527993f8520ba2949fe9e7574c94052c158851ae3ee4ffb0c5e872d17
    Search Simon's blog
    Arguments: {"query": {"type": "string"}}

Tool results

  • search_blog: call_MytYsvzv3pGtfSzUnAjMbq7K

    [{"snippet": "\u2026think you could persist to it, but I don't think you can seek/update/.../all the posix stuff sqlite probably needs</p>\r\n</li>\r\n<li>\r\n<p>Hasura <a href=\"https://github.com/hasura/<mark>graphql</mark>-engine/blob/master/architecture/live-queries.md\">documented</a> how they do reactive queries with Postgres, might be useful for minimising refetch overhead?</p>\r\n</li>\r\n</ul>\r\n<h5>Datasette</h5>\r\n<p><mark>Simon</mark> <mark>Willison</mark> <a href=\"https://twitter.com/simonw\">@simonw</a></p>\r\n<p><a href=\"https://datasette.io/\">Datasette</a> is an open source multi-tool for exploring and publishing data. It explores SQLite as a read\u2026"}, {"snippet": "\u2026Django\r\n\r\nReturns a summary from searching Wikipedia\r\n\r\n<mark>simon</mark>_blog_search:\r\n\r\ne.g. <mark>simon</mark>_blog_search: Django\r\n\r\nSearch <mark>Simon</mark>&#39;s blog for that term\r\n\r\nAlways look things up on Wikipedia if you have the opportunity to do so.\" style=\"max-width: 100%;\" /></p>\r\n<p>The way you \"program\" the LLM for this is you write English text to it!</p>\r\n<p>Here's the prompt I used for my reAct <mark>implementation</mark>. It's the full <mark>implementation</mark> of that system, telling it how to work and describing the abilities it has - searching Wikipedia, running simple calculations and looking things up on\u2026"}]

Response

Tool calls

  • search_blog: call_4ip345HPy5Jxp7kqGcYkNYSR
    Arguments: {"query": "site:simonwillison.net GraphQL Datasette"}
  • search_blog: call_rap5J5RbFUlcwTBpWgrW6THX
    Arguments: {"query": "GraphQL Datasette"}
  • search_blog: call_lAIXhPt6Z9fe9F3xD6zEmPZ0
    Arguments: {"query": "GraphQL"}

Token usage

572 input, 87 output, {"completion_tokens_details": {"reasoning_tokens": 7}}

2026-05-11T18:38:00

Prompt

-- none --

Tools

  • search_blog: 4ea1859527993f8520ba2949fe9e7574c94052c158851ae3ee4ffb0c5e872d17
    Search Simon's blog
    Arguments: {"query": {"type": "string"}}

Tool results

  • search_blog: call_4ip345HPy5Jxp7kqGcYkNYSR

    {"ok": false, "database": "simonwillisonblog", "query_name": null, "rows": [], "truncated": false, "columns": [], "query": {"sql": "\nWITH results AS (\n SELECT 'entry' AS type, blog_entry.id AS id, blog_entry.slug AS slug,\n blog_entry.title AS title, blog_entry.created AS created,\n snippet(blog_entry_fts, -1, '<mark>', '</mark>', '\u2026', 100) AS snippet,\n blog_entry_fts.rank AS rank\n FROM blog_entry_fts JOIN blog_entry ON blog_entry.rowid = blog_entry_fts.rowid\n WHERE blog_entry_fts MATCH :q\n UNION ALL\n SELECT 'blogmark', blog_blogmark.id, blog_blogmark.slug,\n blog_blogmark.link_title, blog_blogmark.created,\n snippet(blog_blogmark_fts, -1, '<mark>', '</mark>', '\u2026', 100),\n blog_blogmark_fts.rank\n FROM blog_blogmark_fts JOIN blog_blogmark ON blog_blogmark.rowid = blog_blogmark_fts.rowid\n WHERE blog_blogmark_fts MATCH :q\n UNION ALL\n SELECT 'quotation', blog_quotation.id, blog_quotation.slug,\n blog_quotation.source, blog_quotation.created,\n snippet(blog_quotation_fts, -1, '<mark>', '</mark>', '\u2026', 100),\n blog_quotation_fts.rank\n FROM blog_quotation_fts JOIN blog_quotation ON blog_quotation.rowid = blog_quotation_fts.rowid\n WHERE blog_quotation_fts MATCH :q\n UNION ALL\n SELECT 'note', id, slug, title, created,\n -- crude snippet: ~100 chars around the first match\n -- becaues this does not yet have FTS enabled\n '\u2026' || substr(body, max(1, instr(lower(body), lower(:q)) - 40), 200) || '\u2026',\n 0.0 -- no real rank available\n FROM blog_note\n WHERE body LIKE '%' || :q || '%' OR title LIKE '%' || :q || '%'\n)\nSELECT snippet FROM results\nORDER BY rank\nLIMIT 20\n", "params": {"q": "site:simonwillison.net GraphQL Datasette"}}, "error": "no such column: site", "private": false, "allow_execute_sql": true, "query_ms": 2.382669999860809, "source": "simonwillison.net", "source_url": "https://simonwillison.net/"}

  • search_blog: call_rap5J5RbFUlcwTBpWgrW6THX

    [{"snippet": "<p>This week I've mostly been building <a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>\"><mark>datasette</mark>-<mark>graphql</mark></a>, a plugin that adds <mark>GraphQL</mark> query support to <mark>Datasette</mark>.</p>\r\n\r\n<p>I've been <a href=\"https://simonwillison.net/search/?q=<mark>graphql</mark>\">mulling this over</a> for a couple of years now. I wasn't at all sure if it would be a good idea, but it's hard to overstate how liberating <mark>Datasette</mark>'s plugin system has proven to be: plugins provide a mechanism for exploring big new ideas without any risk of taking the core project in a direction\u2026"}, {"snippet": "<p>This week I've been working on making <mark>Datasette</mark> easier to install, plus wide-ranging improvements to the <mark>Datasette</mark> <mark>GraphQL</mark> plugin.</p>\r\n<h4 id=\"<mark>datasette</mark>-and-homebrew\"><mark>Datasette</mark> and Homebrew</h4>\r\n<p><mark>Datasette</mark> is now part of the <a href=\"https://github.blog/2020-05-06-new-from-satellite-2020-github-codespaces-github-discussions-securing-code-in-private-repositories-and-more/#discussions\">GitHub Discussions</a> beta - which means the GitHub repository for the project now has a <a href=\"https://github.com/simonw/<mark>datasette</mark>/discussions\"><mark>Datasette</mark> discussions area</a>. I've been wanting to set up somewhere to talk\u2026"}, {"snippet": "<p>This week I built a geospatial search engine for protected areas in California, shipped <mark>datasette</mark>-<mark>graphql</mark> 1.0 and started working towards the next milestone for <mark>Datasette</mark> Cloud.</p>\r\n\r\n<h4 id=\"cpad-in-<mark>datasette</mark>\">California Protected Areas in <mark>Datasette</mark></h4>\r\n\r\n<p>This weekend I learned about CPAD - the <a href=\"https://www.calands.org/cpad/\">California Protected Areas Database</a>. It's a remarkable GIS dataset maintained by <a href=\"https://www.greeninfo.org/\">GreenInfo Network</a>, an Oakland non-profit and released under a Creative Commons Attribution license.</p>\r\n\r\n<p>CPAD is released twice annually as a shapefile\u2026"}, {"snippet": "\u2026This week I mainly worked on <a href=\"https://github.com/simonw/<mark>datasette</mark>-indieauth\"><mark>datasette</mark>-indieauth</a>, but I also gave a keynote at PyCon Argentina and released a version of <a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>\"><mark>datasette</mark>-<mark>graphql</mark></a> with a small security fix.</p>\r\n<h4><mark>datasette</mark>-indieauth</h4>\r\n<p>I wrote about this project in detail in <a href=\"https://simonwillison.net/2020/Nov/18/indieauth/\">Implementing IndieAuth for <mark>Datasette</mark></a> - it was inspired by last weekend's IndieWebCamp East and provides <mark>Datasette</mark> with a password-less sign in option with the least possible amount of\u2026"}, {"snippet": "<p>This week I helped Natalie launch <a href=\"https://www.rockybeaches.com/\">Rocky Beaches</a>, shipped <mark>Datasette</mark> 0.48 and several releases of <code><mark>datasette</mark>-<mark>graphql</mark></code>, upgraded the CSRF protection for <code><mark>datasette</mark>-upload-csvs</code> and figured out how to get a commit log of changes to my blog by backing up its database to a GitHub repository.</p>\r\n<h4 id=\"rocky-beaches\">Rocky Beaches</h4>\r\n<p><a href=\"https://twitter.com/natbat\">Natalie</a> released the first version of <a href=\"https://www.rockybeaches.com/\">rockybeaches.com</a> this week. It's a site that helps\u2026"}, {"snippet": "\u2026<mark>GraphQL</mark> schema scraping</h4>\r\n<p>I've started making selective use of the <a href=\"https://fly.io/\">Fly.io</a> <mark>GraphQL</mark> API as part of <a href=\"https://github.com/simonw/<mark>datasette</mark>-publish-fly\">my plugin</a> for publishing <mark>Datasette</mark> instances to that platform.</p>\r\n<p>Their <mark>GraphQL</mark> API is openly available, but it's not extensively documented - presumably because they reserve the right to make breaking changes to it at any time. I collected some notes on it in this TIL: <a href=\"https://til.simonwillison.net/fly/undocumented-<mark>graphql</mark>-api\">Using the undocumented Fly <mark>GraphQL</mark> API</a\u2026"}, {"snippet": "\u2026It does this by translating <mark>GraphQL</mark> field requests into calls to the <mark>Datasette</mark> table JSON API.</p>\r\n<p>This used to work with some inelegant hijacking of <mark>Datasette</mark>'s undocumented internal view classes, which made me nervous because it meant that the <mark>GraphQL</mark> plugin would break any time I modified <mark>Datasette</mark> core.</p>\r\n<p>In 1.5 I <a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>/commit/289484d9dc40faa76dbd9af24786b3069cb6a75f#diff-e7e272f15568ba13579f704f3832581debbd2ef46ba1d385edacb9c85b172c26L602\">switched it over</a> to using the <code><mark>datasette</mark>.client</code> mechanism instead, which should be a much more stable target since changes to <mark>Datasette</mark>'s JSON API are made\u2026"}, {"snippet": "\u2026github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>\"><mark>datasette</mark>-<mark>graphql</mark></a></strong>: <a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>/releases/tag/2.0.2\">2.0.2</a> - (<a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>/releases\">34 releases total</a>) - 2022-05-30\r\n<br /><mark>Datasette</mark> plugin providing an automatic <mark>GraphQL</mark> API for your SQLite databases</li>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/<mark>datasette</mark>-auth-existing-cookies\"><mark>datasette</mark>-auth-existing-cookies</a></strong>: <a href=\"https://github.com/simonw/<mark>datasette</mark>-auth-existing-cookies/releases/tag/1.0a1\">1.0a1</a> - (<a href=\"https://github.com/simonw/<mark>datasette</mark>-auth-existing-cookies\u2026"}, {"snippet": "A new release of the <mark>datasette</mark>-<mark>graphql</mark> plugin, fixing a minor security flaw: previous versions of the plugin could expose the schema (but not the actual data) of tables in databases that were otherwise protected by <mark>Datasette</mark>'s permission system."}, {"snippet": "\u2026<mark>datasette</mark>-block-robots \\\r\n--install <mark>datasette</mark>-<mark>graphql</mark> \\\r\n--install <mark>datasette</mark>-search-all\r\n</code></pre>\r\n<p>This uses the using <a href=\"https://docs.<mark>datasette</mark>.io/en/stable/publish.html\"><mark>datasette</mark> publish</a> command to deploy the <a href=\"https://<mark>datasette</mark>.simonwillison.net/\"><mark>datasette</mark>.simonwillison.net</a> site to Google Cloud Run.</p>\r\n<p>I'm adding two more plugins here: <a href=\"https://<mark>datasette</mark>.io/plugins/<mark>datasette</mark>-block-robots\"><mark>datasette</mark>-block-robots</a> to avoid search engine crawlers indexing a duplicate copy of my blog's content, and <a href=\"https://<mark>datasette</mark>.io/plugins/<mark>datasette</mark>-<mark>graphql</mark>\"><mark>datasette</mark>-<mark>graphql</mark></a> to enable <mark>GraphQL</mark>\u2026"}, {"snippet": "\u2026Improvements to <code><mark>datasette</mark>-ripgrep</code>, <code>github-to-sqlite</code> and <code><mark>datasette</mark>-<mark>graphql</mark></code>, plus <mark>Datasette</mark> 0.52 and a flurry of dot-releases.</p>\r\n<h4><mark>datasette</mark>-ripgrep 0.5 and 0.6</h4>\r\n<p><a href=\"https://github.com/simonw/<mark>datasette</mark>-ripgrep\"><mark>datasette</mark>-ripgrep</a> (introduced <a href=\"https://simonwillison.net/2020/Nov/28/<mark>datasette</mark>-ripgrep/\">last week</a>) landed <a href=\"https://news.ycombinator.com/item?id=25236636\">on Hacker News</a>, and the comments there inspired me to build a few new features. The interface looks like this now:</p>\r\n<p><a href=\"https://ripgrep\u2026"}, {"snippet": "The first edition of the new <mark>Datasette</mark> Weekly newsletter - covering <mark>Datasette</mark> 0.50, Git scraping, extracting columns with sqlite-utils and featuring <mark>datasette</mark>-<mark>graphql</mark> as the first \"plugin of the week\""}, {"snippet": "\u2026I'll be <a href=\"https://github.com/simonw/<mark>datasette</mark>/issues/1005\">using that in <mark>Datasette</mark></a> as soon as the next httpx version is released.</p>\r\n<h4>TIL this week</h4>\r\n<ul>\r\n<li><a href=\"https://til.simonwillison.net/til/til/javascript_manipulating-query-params.md\">Manipulating query strings with URLSearchParams</a></li>\r\n<li><a href=\"https://til.simonwillison.net/til/til/digitalocean_<mark>datasette</mark>-on-digitalocean-app-platform.md\">Running <mark>Datasette</mark> on DigitalOcean App Platform</a></li>\r\n<li><a href=\"https://til.simonwillison.net/til/til/github_<mark>graphql</mark>-search-topics.md\">Searching for repositories by topic using the GitHub\u2026"}, {"snippet": "\u2026csvs-to-sqlite/releases\">13 releases total</a>) - 2021-11-18\r\n<br />Convert CSV files into a SQLite database</li>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>\"><mark>datasette</mark>-<mark>graphql</mark></a></strong>: <a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>/releases/tag/2.0\">2.0</a> - (<a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>/releases\">32 releases total</a>) - 2021-11-17\r\n<br /><mark>Datasette</mark> plugin providing an automatic <mark>GraphQL</mark> API for your SQLite databases</li>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/asyncinject\">asyncinject</a></strong>: <a href=\"https://github.com/simonw/asyncinject/releases/tag/0\u2026"}, {"snippet": "<p>I published <a href=\"https://<mark>datasette</mark>.io/tutorials\">two new tutorials</a> for <mark>Datasette</mark> this week, both focused at end-users of the web application.</p>\r\n<p><strong><a href=\"https://<mark>datasette</mark>.io/tutorials/explore\">Exploring a database with <mark>Datasette</mark></a></strong> shows how to use <mark>Datasette</mark> as an exploratory data analysis tool, using facets and filters to get a good feeling for a new database.</p>\r\n<p><strong><a href=\"https://<mark>datasette</mark>.io/tutorials/learn-sql\">Learn SQL with <mark>Datasette</mark></a></strong> introduces <mark>Datasette</mark>'s SQL query interface and uses it to teach basic SQL as well as\u2026"}, {"snippet": "\u2026Details <a href=\"https://github.com/simonw/<mark>datasette</mark>/issues/1901\">in this issue</a> - thanks to Brian Grinstead for pointing it out.</p>\r\n<h4>Releases this week</h4>\r\n<ul>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/dclient\">dclient</a></strong>: <a href=\"https://github.com/simonw/dclient/releases/tag/0.1a2\">0.1a2</a> - (<a href=\"https://github.com/simonw/dclient/releases\">3 releases total</a>) - 2022-11-22\r\n<br />A client CLI utility for <mark>Datasette</mark> instances</li>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>\"><mark>datasette</mark>-<mark>graphql</mark></a></strong>: <a href=\"https://github.com/simonw/<mark>datasette</mark>\u2026"}, {"snippet": "\u2026This means I now have a <a href=\"https://github.com/simonw/fivethirtyeight-polls/commits/main\">commit history</a> of changes they have made to their polling data!</p>\r\n<p>I updated my FiveThirtyEight <mark>Datasette</mark> script to publish that data as a new <code>polls.db</code> database, which is now being served at <a href=\"https://fivethirtyeight.<mark>datasettes</mark>.com/polls\">fivethirtyeight.<mark>datasettes</mark>.com/polls</a>.</p>\r\n<p>And since that <mark>Datasette</mark> instance runs the <a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>\"><mark>datasette</mark>-<mark>graphql</mark></a> plugin, you can now use <mark>GraphQL</mark> to explore FiveThirtyEight's most recent polling data\u2026"}, {"snippet": "\u2026explore salaries with <mark>GraphQL</mark></h4>\r\n<p>You may have noticed my <code><mark>datasette</mark> publish</code> line above finished with the line <code>--install <mark>datasette</mark>-<mark>graphql</mark></code>. This installs the <a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>\"><mark>datasette</mark>-<mark>graphql</mark></a> plugin as part of the deployment to Cloud Run. Which means we can query the salary data using <mark>GraphQL</mark> as an alternative to SQL!</p>\r\n<p>Here's a <mark>GraphQL</mark> query that shows the ten highest paid employees, including their various expanded foreign key references:</p>\r\n<div class=\"highlight highlight-source-<mark>graphql</mark>\"><pre>{\r\n <span class=\"pl-v\">salaries</span>(<span\u2026"}, {"snippet": "\u2026Running <code>PRAGMA schema_version</code> against a connection to a database is an extremely fast query.</p>\r\n<p>I first used this trick <a href=\"https://github.com/simonw/<mark>datasette</mark>-<mark>graphql</mark>/issues/51\">in <mark>datasette</mark>-<mark>graphql</mark></a> to cache the results of <mark>GraphQL</mark> schema introspection, so I'm confident it will work here too.</p>\r\n<h4>The problem with permissions</h4>\r\n<p>There's one really gnarly challenge I still need to solve here: permissions.</p>\r\n<p><mark>Datasette</mark>'s <a href=\"https://docs.<mark>datasette</mark>.io/en/stable/authentication.html#permissions\">permissions system</a>, added <a href=\"https://simonwillison.net\u2026"}, {"snippet": "Neat tool for producing an interactive graph visualization of any <mark>GraphQL</mark> API. Click \"Change schema\" and then \"Introspection\" and it will give you a <mark>GraphQL</mark> query you can run against your own API - copy and paste back the JSON results and the visualizer will show you how your API fits together. I tested this against a <mark>datasette</mark>-<mark>graphql</mark> instance and it worked exactly as described."}]

  • search_blog: call_lAIXhPt6Z9fe9F3xD6zEmPZ0

    [{"snippet": "Neat tool for producing an interactive graph visualization of any <mark>GraphQL</mark> API. Click \"Change schema\" and then \"Introspection\" and it will give you a <mark>GraphQL</mark> query you can run against your own API - copy and paste back the JSON results and the visualizer will show you how your API fits together. I tested this against a datasette-<mark>graphql</mark> instance and it worked exactly as described."}, {"snippet": "<p>This week I've mostly been building <a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>\">datasette-<mark>graphql</mark></a>, a plugin that adds <mark>GraphQL</mark> query support to Datasette.</p>\r\n\r\n<p>I've been <a href=\"https://simonwillison.net/search/?q=<mark>graphql</mark>\">mulling this over</a> for a couple of years now. I wasn't at all sure if it would be a good idea, but it's hard to overstate how liberating Datasette's plugin system has proven to be: plugins provide a mechanism for exploring big new ideas without any risk of taking the core project in a direction\u2026"}, {"snippet": "<p>This week I built a geospatial search engine for protected areas in California, shipped datasette-<mark>graphql</mark> 1.0 and started working towards the next milestone for Datasette Cloud.</p>\r\n\r\n<h4 id=\"cpad-in-datasette\">California Protected Areas in Datasette</h4>\r\n\r\n<p>This weekend I learned about CPAD - the <a href=\"https://www.calands.org/cpad/\">California Protected Areas Database</a>. It's a remarkable GIS dataset maintained by <a href=\"https://www.greeninfo.org/\">GreenInfo Network</a>, an Oakland non-profit and released under a Creative Commons Attribution license.</p>\r\n\r\n<p>CPAD is released twice annually as a shapefile\u2026"}, {"snippet": "<p>This week I've been working on making Datasette easier to install, plus wide-ranging improvements to the Datasette <mark>GraphQL</mark> plugin.</p>\r\n<h4 id=\"datasette-and-homebrew\">Datasette and Homebrew</h4>\r\n<p>Datasette is now part of the <a href=\"https://github.blog/2020-05-06-new-from-satellite-2020-github-codespaces-github-discussions-securing-code-in-private-repositories-and-more/#discussions\">GitHub Discussions</a> beta - which means the GitHub repository for the project now has a <a href=\"https://github.com/simonw/datasette/discussions\">Datasette discussions area</a>. I've been wanting to set up somewhere to talk\u2026"}, {"snippet": "\u2026I collected some notes on it in this TIL: <a href=\"https://til.simonwillison.net/fly/undocumented-<mark>graphql</mark>-api\">Using the undocumented Fly <mark>GraphQL</mark> API</a>.</p>\r\n<p>This gave me an idea: could I track changes made to their <mark>GraphQL</mark> schema using the same scraping trick?</p>\r\n<p>It turns out I can! There's an NPM package called <a href=\"https://www.npmjs.com/package/get-<mark>graphql</mark>-schema\">get-<mark>graphql</mark>-schema</a> which can extract the <mark>GraphQL</mark> schema from any <mark>GraphQL</mark> server and write it out to disk:</p>\r\n<pre><code>npx get-<mark>graphql</mark>-schema https://api.fly\u2026"}, {"snippet": "Super Graph is a <mark>GraphQL</mark> server that compiles arbitrarily nested <mark>GraphQL</mark> queries to \"a single fast SQL query\". I've always wondered how that could possible work, so I asked author Vikram Rangnekar for an example of a compiled query - it turns out it uses a brilliant sequence of JSON aggregations to glue together results from nested subqueries and left outer joins."}, {"snippet": "<p>This week I helped Natalie launch <a href=\"https://www.rockybeaches.com/\">Rocky Beaches</a>, shipped Datasette 0.48 and several releases of <code>datasette-<mark>graphql</mark></code>, upgraded the CSRF protection for <code>datasette-upload-csvs</code> and figured out how to get a commit log of changes to my blog by backing up its database to a GitHub repository.</p>\r\n<h4 id=\"rocky-beaches\">Rocky Beaches</h4>\r\n<p><a href=\"https://twitter.com/natbat\">Natalie</a> released the first version of <a href=\"https://www.rockybeaches.com/\">rockybeaches.com</a> this week. It's a site that helps\u2026"}, {"snippet": "\u2026I've had some very productive conversations there about parts of the specification that I found confusing.</p>\r\n<h4>datasette-<mark>graphql</mark></h4>\r\n<p>This week I also issued a security advisory for my datasette-<mark>graphql</mark> plugin. This one was thankfully much less severe: I realized that the plugin was leaking details of the schema of otherwise private databases, if they were protected by Datasette's permission system.</p>\r\n<p>Here's the advisory: <a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>/security/advisories/GHSA-74hv-qjjq-h7g5\">datasette-<mark>graphql</mark> leaks details of the schema of private database files</a>. It\u2026"}, {"snippet": "datasette-<mark>graphql</mark> 1.2"}, {"snippet": "\u2026it <a href=\"https://github.com/dogsheep/dogsheep-beta/blob/0.10.2/dogsheep_beta/__init__.py#L223-L230\">uses that mechanism</a> to make internal API calls to calculate facet counts without re-implementing faceting.</p>\r\n<p><code>datasette-<mark>graphql</mark></code> exposes a <mark>GraphQL</mark> API over Datasette tables, including the ability to apply filters (rows where age &gt; 25 etc). It does this by translating <mark>GraphQL</mark> field requests into calls to the Datasette table JSON API.</p>\r\n<p>This used to work with some inelegant hijacking of Datasette's undocumented internal view classes, which made me nervous because it\u2026"}, {"snippet": "\u2026PUBLIC) {\r\n pageInfo {\r\n hasNextPage\r\n endCursor\r\n }\r\n nodes {\r\n name\r\n releases(last:1) {\r\n totalCount\r\n nodes {\r\n name\r\n publishedAt\r\n url\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}</code></pre>\r\n\r\n<p>This query returns the most recent release (<code>last:1</code>) for each of the first 100 of my public repositories.</p>\r\n\r\n<p>You can paste it into the <a href=\"https://developer.github.com/v4/explorer/\">GitHub <mark>GraphQL</mark> explorer</a> to run it against your own profile.</p>\r\n\r\n<p>There's just one catch: pagination. I have more than 100 repos but their <mark>GraphQL</mark> can only return 100 nodes at a time.</p>\r\n\r\n<p>To paginate, you need to request the <code\u2026"}, {"snippet": "\u2026tag/0.1a0\">0.1a0</a> - 2022-05-31\r\n<br />Load email from .mbox files into SQLite</li>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>\">datasette-<mark>graphql</mark></a></strong>: <a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>/releases/tag/2.0.2\">2.0.2</a> - (<a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>/releases\">34 releases total</a>) - 2022-05-30\r\n<br />Datasette plugin providing an automatic <mark>GraphQL</mark> API for your SQLite databases</li>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/datasette-auth-existing-cookies\">datasette-auth-existing-cookies</a></strong>: <a href=\"https://github\u2026"}, {"snippet": "I've seen many of these criticisms of <mark>GraphQL</mark> before - N+1 queries, the difficulty of protecting against deeply nested queries - but Matt Bessey collects them all in one place and adds an issue I hadn't considered before: the complexity of authorization, where each field in the query might involve extra permission checks:\r\n\r\n> In my experience, this is actually **the biggest source of performance issues**. We would regularly find that our queries were spending more time authorising data than anything else.\r\n\r\nThe 600+ comment [Hacker News thread](https://news.ycombinator.com/item?id=40521518) is crammed with <mark>GraphQL</mark> war\u2026"}, {"snippet": "\u2026The example query now demonstrates the most interesting feature of <code>datasette-<mark>graphql</mark></code> - its ability to automatically <a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>#accessing-nested-objects\">convert foreign key relationships</a> in your database into nested <mark>GraphQL</mark> fields.</p>\r\n<p>It's a small change, but it makes me really happy.</p>\r\n<h4>Datasette 0.52</h4>\r\n<p>I shipped <a href=\"\">Datasette 0.52</a>, a relatively minor release which mainly kicked off an effort to rebrand \"configuration\" as \"settings\".</p>\r\n<p>I'm doing this as part of my effort to fix Datasette's \"metadata\u2026"}, {"snippet": "\u2026packages/releases\">3 releases total</a>) - 2022-07-03\r\n<br />Show a list of currently installed Python packages</li>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>\">datasette-<mark>graphql</mark></a></strong>: <a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>/releases/tag/2.1\">2.1</a> - (<a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>/releases\">35 releases total</a>) - 2022-07-03\r\n<br />Datasette plugin providing an automatic <mark>GraphQL</mark> API for your SQLite databases</li>\r\n<li>\r\n<strong><a href=\"https://github.com/simonw/datasette-edit-schema\">datasette-edit-schema</a></strong>: <a href=\"https://github.com/simonw/datasette\u2026"}, {"snippet": "PostGraphile is a tool for building a <mark>GraphQL</mark> API on top of an existing PostgreSQL schema. Their \"production considerations\" documentation is particularly interesting because it directly addresses some of my biggest worries about <mark>GraphQL</mark>: the potential for someone to craft an expensive query that ties up server resources. PostGraphile suggests a number of techniques for avoiding this, including a statement timeout, a query allowlist, pagination caps and (in their \"pro\" version) a cost limit that uses a calculated cost score for the query."}, {"snippet": "\u2026explore salaries with <mark>GraphQL</mark></h4>\r\n<p>You may have noticed my <code>datasette publish</code> line above finished with the line <code>--install datasette-<mark>graphql</mark></code>. This installs the <a href=\"https://github.com/simonw/datasette-<mark>graphql</mark>\">datasette-<mark>graphql</mark></a> plugin as part of the deployment to Cloud Run. Which means we can query the salary data using <mark>GraphQL</mark> as an alternative to SQL!</p>\r\n<p>Here's a <mark>GraphQL</mark> query that shows the ten highest paid employees, including their various expanded foreign key references:</p>\r\n<div class=\"highlight highlight-source-<mark>graphql</mark>\"><pre>{\r\n <span class=\"pl-v\">salaries</span>(<span\u2026"}, {"snippet": "SQL is a better API language than <mark>GraphQL</mark> \u2013 Convince me otherwise"}, {"snippet": "\u2026I'll be <a href=\"https://github.com/simonw/datasette/issues/1005\">using that in Datasette</a> as soon as the next httpx version is released.</p>\r\n<h4>TIL this week</h4>\r\n<ul>\r\n<li><a href=\"https://til.simonwillison.net/til/til/javascript_manipulating-query-params.md\">Manipulating query strings with URLSearchParams</a></li>\r\n<li><a href=\"https://til.simonwillison.net/til/til/digitalocean_datasette-on-digitalocean-app-platform.md\">Running Datasette on DigitalOcean App Platform</a></li>\r\n<li><a href=\"https://til.simonwillison.net/til/til/github_<mark>graphql</mark>-search-topics.md\">Searching for repositories by topic using the GitHub\u2026"}, {"snippet": "The first edition of the new Datasette Weekly newsletter - covering Datasette 0.50, Git scraping, extracting columns with sqlite-utils and featuring datasette-<mark>graphql</mark> as the first \"plugin of the week\""}]

Response

Yes. Simon implemented GraphQL support for Datasette as a plugin called datasette-graphql.

He described it as “a plugin that adds GraphQL query support to Datasette,” and later as a “Datasette plugin providing an automatic GraphQL API for your SQLite databases.” It can expose Datasette tables through GraphQL, including nested fields based on foreign-key relationships.

Token usage

8,395 input, 216 output, {"completion_tokens_details": {"reasoning_tokens": 129}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment