{"id":8334,"date":"2026-01-23T10:51:50","date_gmt":"2026-01-23T15:51:50","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=8334"},"modified":"2026-01-28T09:27:37","modified_gmt":"2026-01-28T14:27:37","slug":"single-flight-mutations-in-tanstack-start-part-1","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/single-flight-mutations-in-tanstack-start-part-1\/","title":{"rendered":"Single Flight Mutations in TanStack Start: Part 1"},"content":{"rendered":"\n<p>A <strong>&#8220;single flight mutation&#8221;<\/strong> is a fancy way of saying: mutate the data <em>and <\/em>update the UI with just <em>one<\/em> round trip to the network.<\/p>\n\n\n\n<p>The beautiful thing about implementing this with TanStack is that we can leverage the tools we already know, and love: <a href=\"https:\/\/tanstack.com\/query\/latest\">TanStack Query<\/a> (formerly react-query), <a href=\"https:\/\/tanstack.com\/router\/latest\">TanStack Router<\/a>, and <a href=\"https:\/\/tanstack.com\/start\/latest\">TanStack Start<\/a>.<\/p>\n\n\n\n<p>If you&#8217;re not familiar with these tools, TanStack Router is a client-only SPA framework (see my <a href=\"https:\/\/frontendmasters.com\/blog\/introducing-tanstack-router\/\">three-part introduction series<\/a>). TanStack Start is a server layer for Router that enables things like SSR, API routes, and server functions (see my <a href=\"https:\/\/frontendmasters.com\/blog\/introducing-tanstack-start\/\">introduction for it<\/a> and <a href=\"https:\/\/frontendmasters.com\/blog\/introducing-tanstack-start-middleware\/\">a post on its middleware feature<\/a>).<\/p>\n\n\n\n<p>I&#8217;ve never written about TanStack Query, but it&#8217;s one of the most widely used React libraries, and there are tons of resources about it. One of the best would be <a href=\"https:\/\/tkdodo.eu\/blog\/all\">TkDodo&#8217;s blog<\/a>. He&#8217;s the lead maintainer of TanStack Query, and his blog is superb.<\/p>\n\n\n\n<p>In this first post, we&#8217;ll cover some fundamentals and then implement the simplest imaginable single flight mutation with a TanStack Start Server Function. In the next part, we&#8217;ll dive deep into middleware and implement a more serious solution, while having some fun with TypeScript in the process.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/single-flight-mutations-in-tanstack-start-part-1\/\">Single Flight Mutations in TanStack Start: Part 1<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/single-flight-mutations-in-tanstack-start-part-2\/\">Single Flight Mutations in TanStack Start: Part 2<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"laying-the-groundwork\">Laying the Groundwork<\/h2>\n\n\n\n<p>In my&nbsp;<a href=\"https:\/\/frontendmasters.com\/blog\/introducing-tanstack-start\/\">post on TanStack Start<\/a>, I included this image, which is how client-driven single-page applications (SPAs) almost always behave.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/01\/img1.png?ssl=1\" alt=\"A flow diagram illustrating the sequence of actions between a browser and a web server when loading a webpage, highlighting the steps of rendering an empty app shell, loading scripts, requesting data, and finally displaying the full page.\" style=\"width:500px;height:auto\"\/><\/figure>\n<\/div>\n\n\n<p>The initial request for whatever URL you&#8217;re viewing returns an empty skeleton of a page. From there, more networks requests happen to fetch scripts and styles, and most likely some data, which eventually results in your actual content page being rendered.<\/p>\n\n\n\n<p>The network round trips will almost always be the single most expensive thing your web application will do. To look at it another way, there are few things you can do to improve performance as much as <em>removing<\/em> network roundtrips. And this is why server-side rendering can be so beneficial: it allows us to display content to our users <em>immediately<\/em>, after the initial request is responded to.<\/p>\n\n\n\n<p>I expressed this in the Start post with this image.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/01\/img2.png?ssl=1\" alt=\"Diagram illustrating the sequence of actions in client-driven single-page applications, showing the initial GET request for an HTML document, followed by script file requests, and the transition from page display to interactivity.\" style=\"width:504px;height:auto\"\/><\/figure>\n<\/div>\n\n\n<p>Those scripts and styles still have to load for your page to be interactive, but that initial response from the server can immediately display content for the user.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"why-single-flight-mutations\">Why Single Flight Mutations<\/h2>\n\n\n\n<p>Let&#8217;s think about how you&#8217;d normally update a piece of data in a web application.<\/p>\n\n\n\n<p>You probably make a network request to some sort of&nbsp;<code>\/update<\/code>&nbsp;endpoint, along with a post packet for whatever you&#8217;re trying to change. The endpoint will probably return a success flag, possibly with the actual piece of data you just updated. Your UI will usually then request updated data. You might think that returning the updated piece of data you just changed is all you&#8217;d need in order to update the UI, but frequently that&#8217;s not the case.<\/p>\n\n\n\n<p>Imagine you&#8217;re looking at a list of TODO tasks, and you just edited one of them. Just updating the item on the screen isn&#8217;t good enough; maybe the edit causes this TODO to no longer even be in this list, depending on your filters. Or perhaps your edit causes this TODO to move to a different page in your results, based on your sort order. Or maybe you just&nbsp;<em>created<\/em>&nbsp;a&nbsp;<em>brand new<\/em>&nbsp;todo. In that case, who knows where, or even&nbsp;<em>if<\/em>&nbsp;this todo will show up in your list, again based on your filters and sorts.<\/p>\n\n\n\n<p>So we re-fetch whatever query produces our list. It usually looks like this<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img data-recalc-dims=\"1\" height=\"922\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/01\/img3.png?resize=1024%2C922&#038;ssl=1\" alt=\"A flowchart illustrating the interaction between a browser and web server, detailing the process of posting updated data, receiving an update result, requesting updated data, and updating the UI accordingly.\" style=\"width:548px;height:auto\"\/><\/figure>\n<\/div>\n\n\n<p>This works, and if we&#8217;re honest with ourselves, it&#8217;s usually good enough. But can we do better? We wouldn&#8217;t be good engineers if we didn&#8217;t at least <em>try<\/em>. Conceptually we&#8217;d like to get something like this<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/01\/img4.png?ssl=1\" alt=\"A diagram illustrating the flow of data between the browser and web server during a single flight mutation. It shows a POST request to '\/update-data' from the browser, followed by a response that includes both the result and new data for UI updates.\" style=\"aspect-ratio:1.1229477378117558;width:587px;height:auto\"\/><\/figure>\n<\/div>\n\n\n<p>We&#8217;ll implement a dead simple solution to this here in part 1, and then part 2 will discuss increasingly flexible ways of accomplishing it with middleware.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"our-app\">Our App<\/h2>\n\n\n\n<p>As with prior posts about TanStack Start and Router, this post will use our cheap, simple, and frankly ugly Jira clone. <a href=\"https:\/\/github.com\/arackaf\/tanstack-start-single-flight-mutations-blog-post\">Here&#8217;s a repo for it<\/a>. It&#8217;s a trivial app that runs on an SQLite database. The epics page looks like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img data-recalc-dims=\"1\" height=\"1024\" width=\"830\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/01\/img5.png?resize=830%2C1024&#038;ssl=1\" alt=\"Screenshot of a web application displaying an overview of epics with a list of tasks, including buttons for viewing and editing.\" style=\"width:476px;height:auto\"\/><\/figure>\n<\/div>\n\n\n<p>As you can see, zero effort was put into the design. But there&#8217;s a few sources of data on the screen, which will help us implement single flight mutations: the main list of epics; the count of all epics (12) just above the list; and above that we have a summary list of epics, with the numbers of tasks therein.<\/p>\n\n\n\n<p>This is the page we&#8217;ll be focusing on for this post. If you&#8217;re following along at home, you can run the app with <code>npm run dev<\/code> and then visit <a href=\"http:\/\/localhost:3000\/app\/epics\">http:\/\/localhost:3000\/app\/epics<\/a>.<\/p>\n\n\n\n<p>Our queries for our list of epics and our summary data are driven by react-query. I&#8217;ve put the query options into helper utilities, like so.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> epicsQueryOptions = <span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">page<\/span>: <span class=\"hljs-params\">number<\/span><\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> queryOptions({\n    queryKey: &#91;<span class=\"hljs-string\">\"epics\"<\/span>, <span class=\"hljs-string\">\"list\"<\/span>, page],\n    queryFn: <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n      <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> getEpicsList({ data: page });\n      <span class=\"hljs-keyword\">return<\/span> result;\n    },\n    staleTime: <span class=\"hljs-number\">1000<\/span> * <span class=\"hljs-number\">60<\/span> * <span class=\"hljs-number\">5<\/span>,\n    gcTime: <span class=\"hljs-number\">1000<\/span> * <span class=\"hljs-number\">60<\/span> * <span class=\"hljs-number\">5<\/span>,\n  });\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This allows me to query data using the normal <code>useQuery<\/code> or <code>useSuspenseQuery<\/code> hook.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">const<\/span> { data: epicsData } = useSuspenseQuery(epicsQueryOptions(deferredPage));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And also prefetch these queries in TanStack loaders, without duplicating code.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\">  <span class=\"hljs-keyword\">async<\/span> loader({ context, deps }) {\n    <span class=\"hljs-keyword\">const<\/span> queryClient = context.queryClient;\n\n    queryClient.ensureQueryData(epicsQueryOptions(deps.page));\n    queryClient.ensureQueryData(epicsCountQueryOptions());\n  },<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>As you can see, this query (and all our other queries) are just straight calls to a single server function (<code>getEpicsList<\/code> in this case), with the result passed through. This is a key detail that will come in handy in part 2.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"simplest-possible-single-flight-mutation\">Simplest Possible Single Flight Mutation<\/h2>\n\n\n\n<p>Let&#8217;s implement a dirt simple single flight mutation, and then iterate on it, to make it more and more scalable. Our main epics page has an edit button, which allows for inline editing.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img data-recalc-dims=\"1\" height=\"1024\" width=\"792\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/01\/img6.png?resize=792%2C1024&#038;ssl=1\" alt=\"A user interface displaying a list of epics with their respective task counts, including buttons for viewing and editing each epic.\" style=\"width:501px;height:auto\"\/><\/figure>\n<\/div>\n\n\n<p>When we hit save, let&#8217;s just refetch the list of epics, as well as the epics summary data inside the edit epic server function, and send those new data down to the client, so the client can update the UI.<\/p>\n\n\n\n<p>Here&#8217;s the entire server function:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> updateWithSimpleRefetch = createServerFn({ method: <span class=\"hljs-string\">\"POST\"<\/span> })\n  .inputValidator(<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">obj<\/span>: { <span class=\"hljs-params\">id<\/span>: <span class=\"hljs-params\">number<\/span>; <span class=\"hljs-params\">name<\/span>: <span class=\"hljs-params\">string<\/span> }<\/span>) =&gt;<\/span> obj)\n  .handler(<span class=\"hljs-keyword\">async<\/span> ({ data }) =&gt; {\n    <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Promise<\/span>(<span class=\"hljs-function\"><span class=\"hljs-params\">resolve<\/span> =&gt;<\/span> setTimeout(resolve, <span class=\"hljs-number\">1000<\/span> * <span class=\"hljs-built_in\">Math<\/span>.random()));\n    <span class=\"hljs-keyword\">await<\/span> db.update(epicsTable).set({ name: data.name }).where(eq(epicsTable.id, data.id));\n\n    <span class=\"hljs-keyword\">const<\/span> &#91;epicsList, epicsSummaryData] = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-built_in\">Promise<\/span>.all(&#91;getEpicsList({ data: <span class=\"hljs-number\">1<\/span> }), getEpicsSummary()]);\n\n    <span class=\"hljs-keyword\">return<\/span> { epicsList, epicsSummaryData };\n  });<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We save our epic, and then fetch the updated data from the&nbsp;<code>getEpicsList<\/code>, and <code>getEpicsSummary<\/code> server functions, which we call in parallel with&nbsp;<code>Promise.all<\/code>. Note that a production-ready application would likely have some error handling.<\/p>\n\n\n\n<p>Now when we call our server function, the data for those queries will be attached to the result. In fact, since we&#8217;re using server functions, these things will even be statically typed!<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" height=\"150\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/01\/img7.png?resize=1024%2C150&#038;ssl=1\" alt=\"Code snippet displaying a loop over result.epicsList with properties of each epic highlighted, showing 'id' and 'name' attributes.\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"updating-the-ui\">Updating the UI<\/h2>\n\n\n\n<p>With updated data for our queries coming back after the save, we can now insert it back into the UI. TanStack Query makes this simple. We need a reference to the QueryClient:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">const<\/span> queryClient = useQueryClient();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then we can update the query payload for a given query with the <code>setQueryData<\/code> method. It takes the query key and the data.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">const<\/span> handleSaveSimple = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> newValue = inputRef.current?.value || <span class=\"hljs-string\">\"\"<\/span>;\n  <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> runSaveSimple({\n    data: {\n      id: epic.id,\n      name: newValue,\n    },\n  });\n\n  queryClient.setQueryData(&#91;<span class=\"hljs-string\">\"epics\"<\/span>, <span class=\"hljs-string\">\"list\"<\/span>, <span class=\"hljs-number\">1<\/span>], result.epicsList);\n  queryClient.setQueryData(&#91;<span class=\"hljs-string\">\"epics\"<\/span>, <span class=\"hljs-string\">\"list\"<\/span>, <span class=\"hljs-string\">\"summary\"<\/span>], result.epicsSummaryData);\n\n  setIsEditing(<span class=\"hljs-literal\">false<\/span>);\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If hard-coding those query keys feels gross to you, don&#8217;t forget about those helper utilities we added before.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\">queryClient.setQueryData(epicsQueryOptions(<span class=\"hljs-number\">1<\/span>).queryKey, result.epicsList, { updatedAt: <span class=\"hljs-built_in\">Date<\/span>.now() });\nqueryClient.setQueryData(epicsSummaryQueryOptions().queryKey, result.epicsSummaryData, { updatedAt: <span class=\"hljs-built_in\">Date<\/span>.now() });<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\" id=\"iterating\">Iterating<\/h2>\n\n\n\n<p>Our solution works, but it&#8217;s fragile. Our server function hard codes which data to fetch. What if our update function were to be called from different parts of the UI, which each needed different slices of data to be refetched? We certainly don&#8217;t want to redefine our server function N times, for each place it needs to be called.<\/p>\n\n\n\n<p>Fortunately, TanStack has the perfect feature to help reduce this coupling: Middleware. We can remove the refetching from the server function, and move it to a reusable middleware which can be attached to server functions.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/single-flight-mutations-in-tanstack-start-part-1\/\">Single Flight Mutations in TanStack Start: Part 1<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/single-flight-mutations-in-tanstack-start-part-2\/\">Single Flight Mutations in TanStack Start: Part 2<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>What if we could mutate data *and* get all the data back we need to properly update the UI in just one network round-trip?<\/p>\n","protected":false},"author":21,"featured_media":8372,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[3,440,240,184],"class_list":["post-8334","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-javascript","tag-mutations","tag-tanstack","tag-typescript"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/01\/tanstack-round-trip.jpg?fit=2000%2C1200&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/8334","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=8334"}],"version-history":[{"count":16,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/8334\/revisions"}],"predecessor-version":[{"id":8418,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/8334\/revisions\/8418"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/8372"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=8334"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=8334"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=8334"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}