[{"data":1,"prerenderedAt":113},["ShallowReactive",2],{"article-\u002Fwriting\u002Fjsonapi-views-120-20260812":3},{"id":4,"title":5,"articleType":6,"categories":7,"date":11,"description":12,"extension":13,"meta":14,"paragraphs":15,"path":108,"readingTime":109,"sitemap":110,"stem":111,"__hash__":112},"articleEntries\u002Farticles-data\u002Fjsonapi-views-120-20260812.json","JSON:API Views 8.x-1.2","Blog post",[8,9,10],"Drupal","Druxt","Planet Drupal","2026-08-12T20:00:00+10:00","JSON:API gets you entities, not listings - JSON:API Views exposes any Drupal View as a JSON:API resource. 8.x-1.2: faster route building on view-heavy sites, cache headers that actually invalidate, a corrected preview URL, and a reworked OpenAPI fix.","json",{},[16,28,60,76,82],{"type":17,"layout":18,"regions":19},"section","layout_onecol",{"content":20},[21,24,26],{"type":22,"html":23},"text_formatted","\u003Cp>JSON:API on its own gets you decoupled entities: fetch a node, fetch a set of IDs, done. It doesn't get you the filtering, sorting and pagination that most real content listings actually need - a list of articles by tag, a paginated product catalogue, an events calendar with a date filter. You either reimplement that logic on the frontend, or Drupal ships a hand-written custom resource for every list on the site. That gap is the same regardless of what's rendering on the other end, React and Next.js, Vue and Nuxt, or anything else that can call an API.\u003C\u002Fp>\n\n\u003Cp>JSON:API Views closes it: whatever a View can already do, a decoupled frontend can ask for over JSON:API, using the access checks and query logic the view already has, no separate endpoint to write or maintain. It's also, not coincidentally, why I still maintain the module at all: it's the backend half of DruxtViews, the piece that makes Views work in Druxt, my own Nuxt-based decoupled Drupal framework.\u003C\u002Fp>",{"type":22,"html":25},"\u003Cp>8.x-1.2 lands six fixes, five of which already had a patch sitting in the queue: route building that's dramatically faster on sites with a lot of exposed views, a preview URL that finally matches what an exposed filter is actually configured to accept, a caching fix so front-end caches actually invalidate, a routing crash tied to numeric bundle names, and a reworked fix for an OpenAPI export crash. Just fixes, no updating required.\u003C\u002Fp>",{"type":22,"html":27},"\u003Cp>JSON:API Views isn't mine originally. \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fu\u002Fpixelwhip\">pixelwhip\u003C\u002Fa> built the module and shipped its first releases; I took over maintenance after that, and 8.x-1.2 is the first release I've cut on the 1.x line. Thanks to pixelwhip for building the thing in the first place.\u003C\u002Fp>",{"type":17,"title":29,"layout":18,"regions":30},"If you haven't used it before",{"content":31},[32,34,41,43,49,51,55,57],{"type":22,"html":33},"\u003Cp>Views is what most Drupal sites already lean on for anything with filtering, sorting or pagination baked in: a list of articles by tag, a paginated product catalogue, an events calendar with a date filter. JSON:API on its own gets a decoupled frontend entities, but it doesn't know about any of that. JSON:API Views bridges the two: enable it on a display and Drupal generates a route for it under \u003Ccode>\u002Fjsonapi\u002Fviews\u002F{view_id}\u002F{display_id}\u003C\u002Fcode>, backed by the same query, filters and access checks the display already has.\u003C\u002Fp>",{"type":35,"alt":36,"caption":37,"width":38,"height":39,"src":40},"media","The 'Expose via JSON:API' checkbox on a view display's settings, checked by default, with the description 'Controls exposure the view with JSON:API.'","Every display ships exposed by default. One checkbox turns it off (for now, see What's next below).",960,254,"\u002Fimages\u002Fwriting\u002Fjsonapi-views-expose-checkbox.png",{"type":22,"html":42},"\u003Cp>The preview panel in the Views UI picks it up too, once a display is exposed: the same query info table that already shows you the page's path grows a JSON:API Views row with the live URL for that display, arguments and exposed filter values included.\u003C\u002Fp>",{"type":35,"alt":44,"caption":45,"width":46,"height":47,"src":48},"The Views UI preview panel's query info table, showing Title, Path, and a JSON:API Views row linking to \u002Fjsonapi\u002Fviews\u002Ffrontpage\u002Fpage_1","The generated JSON:API endpoint for a view, right there in the Views UI preview panel.",886,137,"\u002Fimages\u002Fwriting\u002Fjsonapi-views-preview-url.png",{"type":22,"html":50},"\u003Cp>Hit that URL and it's a normal JSON:API response, whatever content types the view actually mixes together:\u003C\u002Fp>",{"type":52,"title":53,"code":54},"code","GET \u002Fjsonapi\u002Fviews\u002Ffrontpage\u002Fpage_1","{\n  \"data\": [\n    {\n      \"type\": \"node--page\",\n      \"id\": \"19e113d5-c838-43e1-ba75-1def5466e3de\",\n      \"attributes\": {\n        \"title\": \"About this site\",\n        \"status\": true,\n        \"created\": \"2026-08-09T09:07:37+00:00\"\n      }\n    },\n    {\n      \"type\": \"node--article\",\n      \"id\": \"62c2d25d-93c9-438b-8bdf-a75b69d05dc5\",\n      \"attributes\": {\n        \"title\": \"Building decoupled Views with jsonapi_views\",\n        \"status\": true,\n        \"created\": \"2026-08-08T10:18:06+00:00\"\n      }\n    }\n  ],\n  \"meta\": { \"count\": \"2\" }\n}",{"type":22,"html":56},"\u003Cp>On the frontend, \u003Ca href=\"https:\u002F\u002Fdruxtjs.org\">Druxt\u003C\u002Fa>'s \u003Ccode>&lt;DruxtView&gt;\u003C\u002Fcode> component renders that exact route as Vue components, filters, sorting and pagination included, no custom resource on either side. It's the frontend half of the same pipeline. DruxtViews targets Nuxt 2 today; a Nuxt 3\u002F4-compatible Druxt is actively in progress, more on that soon.\u003C\u002Fp>",{"type":52,"title":58,"code":59},"Render a View with Druxt","\u003CDruxtView view-id=\"frontpage\" display-id=\"page_1\" \u002F>",{"type":17,"title":61,"layout":18,"regions":62},"What's fixed",{"content":63},[64,66,68,70,72,74],{"type":22,"html":65},"\u003Cp>Five bug fixes, with a big thanks to the community whose patches made most of them possible:\u003C\u002Fp>",{"type":22,"html":67},"\u003Cp>\u003Cstrong>Cache headers weren't being set\u003C\u002Fstrong> (\u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fproject\u002Fjsonapi_views\u002Fissues\u002F3202583\">#3202583\u003C\u002Fa>, patch by \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fu\u002Fyahyaalhamad\">yahyaalhamad\u003C\u002Fa>). View cache tags weren't reaching the JSON:API response's headers, so a page cache in front of the site never invalidated when the underlying content changed. Fixed by pushing the tags onto the response's bubbleable metadata.\u003C\u002Fp>",{"type":22,"html":69},"\u003Cp>\u003Cstrong>Route building got slow with a lot of exposed views\u003C\u002Fstrong> (\u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fproject\u002Fjsonapi_views\u002Fissues\u002F3484714\">#3484714\u003C\u002Fa>, patch by \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fu\u002Fjacobbell84\">jacobbell84\u003C\u002Fa>). Every rebuild looked up each view's resource type from scratch, once per view per entity type. Caching it per entity type instead: 637 calls to \u003Ccode>ResourceTypeRepository::get()\u003C\u002Fcode> down to 13, at the scale the issue reported.\u003C\u002Fp>",{"type":22,"html":71},"\u003Cp>\u003Cstrong>Numeric bundle machine names broke routing entirely\u003C\u002Fstrong> (\u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fproject\u002Fjsonapi_views\u002Fissues\u002F3503402\">#3503402\u003C\u002Fa>, patch by \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fu\u002Fchodec\">chodec\u003C\u002Fa>). An all-digit bundle machine name threw an \u003Ccode>AssertionError\u003C\u002Fcode> during route building instead of returning a route. Cast to string before the lookup, fixed.\u003C\u002Fp>",{"type":22,"html":73},"\u003Cp>\u003Cstrong>The preview URL used the wrong query parameter\u003C\u002Fstrong> (\u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fproject\u002Fjsonapi_views\u002Fissues\u002F3376193\">#3376193\u003C\u002Fa>, patch by \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fu\u002Fjeffschuler\">jeffschuler\u003C\u002Fa>). The Views UI preview panel was reading an exposed filter's field name instead of its configured identifier, breaking any view where you'd renamed a filter to something readable. It now reads the identifier the display is actually configured with.\u003C\u002Fp>",{"type":22,"html":75},"\u003Cp>\u003Cstrong>OpenAPI schema export crashed with jsonapi_views enabled\u003C\u002Fstrong> (\u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fproject\u002Fjsonapi_views\u002Fissues\u002F3265781\">#3265781\u003C\u002Fa>). jsonapi_views now reports a view's real \u003Ccode>ResourceType\u003C\u002Fcode> on the route when its entity type has exactly one bundle, so OpenAPI describes it correctly; multi-bundle views are left alone.\u003C\u002Fp>",{"type":17,"title":77,"layout":18,"regions":78},"What's next",{"content":79},[80],{"type":22,"html":81},"\u003Cp>This is part of the same push that got Field Tokens 2.0.0 and Custom Formatters 4.1.0 out the door: working through my modules one at a time and actually clearing the backlog, not just triaging it. There's more coming for JSON:API Views too, tighter access control at the route level, more performance headroom for sites well past a hundred exposed views, and eventually a 2.0.x that flips exposure from opt-out to opt-in. File (Field) Paths is next up though, tens of thousands of sites and still sitting in RC ahead of a stable 1.0.\u003C\u002Fp>",{"type":17,"layout":18,"regions":83},{"content":84},[85,96,98,100,106],{"type":86,"title":87,"content":88},"jumbotron","If your project depends on this work",[89,91],{"type":22,"html":90},"\u003Cp>JSON:API Views, the wider Druxt ecosystem, the other modules I maintain - I build all of it in the open, and sponsorship is what keeps it actively maintained.\u003C\u002Fp>",{"type":92,"link":93},"link",{"href":94,"label":95},"https:\u002F\u002Fgithub.com\u002Fsponsors\u002FDecipher","Sponsor on GitHub",{"type":22,"html":97},"\u003Cp>If any of this is useful to you, 8.x-1.2 is out now:\u003C\u002Fp>",{"type":52,"code":99},"composer require 'drupal\u002Fjsonapi_views:^1.2'",{"type":101,"description":102,"url":103,"gitpod":104,"drupalUrl":105},"repository","Source on GitHub, project page on Drupal.org, patches welcome in the issue queue. If your project depends on this, sponsoring keeps it actively maintained.","https:\u002F\u002Fgithub.com\u002FDecipher\u002Fjsonapi_views",false,"https:\u002F\u002Fwww.drupal.org\u002Fproject\u002Fjsonapi_views",{"type":22,"html":107},"\u003Cp>What's your decoupled stack - are you hand-rolling a listing endpoint for every view, or reaching for something like this? I'd genuinely like to know.\u003C\u002Fp>","\u002Fwriting\u002Fjsonapi-views-120-20260812","6 min",{"loc":108},"articles-data\u002Fjsonapi-views-120-20260812","IsRHTHtqIKYhqX2U3Spkek9suuSbvuZjZBeYs_Gog8c",1786513039849]