{"id":692,"date":"2021-01-27T17:40:00","date_gmt":"2021-01-27T04:40:00","guid":{"rendered":"https:\/\/blog.wiseowls.co.nz\/?p=692"},"modified":"2021-08-19T01:24:16","modified_gmt":"2021-08-18T12:24:16","slug":"approaches-to-handling-simple-expressions-in-c","status":"publish","type":"post","link":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/","title":{"rendered":"Approaches to handling simple expressions in C#"},"content":{"rendered":"\n<p>Every now and then we get asked if there&#8217;s an easy way to parse user input into filter conditions. Say, for example, we have a viewmodel of type <code>DataThing<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"csharp\" class=\"language-csharp\">public class DataThing\n {\n     public string Name;\n     public float Value;\n     public int Count;\n }<\/code><\/pre>\n\n\n\n<p>From here we&#8217;d like to check if a given property of this class satisfies a certain condition. For example we&#8217;ll look at &#8220;Value is greater than 15&#8221;. But of course we&#8217;d like to be flexible.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The issue<\/h2>\n\n\n\n<p>The main issue here is we don&#8217;t know the type of property before hand, so we can&#8217;t use generics even if we try to be smart:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"csharp\" class=\"language-csharp\">public class DataThing\n {\n     public string Name;\n     public float Value;\n     public int Count;\n }\n public static void Main()\n {\n     var data = new DataThing() {Value=10, Name=\"test\", Count = 1};\n     var values = new List {\n         new ValueGetter(x => x.Value),\n         new ValueGetter(x => x.Name)\n     };\n     (values[0].Run(data) > 15).Dump();\n }\n public abstract class ValueGetter\n {\n     public abstract T Run&lt;T>(DataThing d);\n }\n public class ValueGetter&lt;T> : ValueGetter\n {\n     public Func&lt;DataThing, T> TestFunc;\n     public ValueGetter(Func&lt;DataThing, T> blah)\n     {\n         TestFunc = blah;\n     }\n     public override T Run(DataThing d) => TestFunc.Invoke(d); \/\/ CS0029 Cannot implicitly convert type\u2026\n }<\/code><\/pre>\n\n\n\n<p>Even if we figured it out it&#8217;s obviously way too dependant on <code>DataThing<\/code> layout to be used everywhere.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">LINQ Expression trees<\/h2>\n\n\n\n<p>One way to solve this issue is with the help of LINQ expression trees. This way we wrap everything into one delegate with predictable signature and figure out types at runtime:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"csharp\" class=\"language-csharp\"> bool BuildComparer(DataThing data, string field, string op, T value) {    \n     var p1 = Expression.Parameter(typeof(DataThing));\n     var p2 = Expression.Parameter(typeof(T));\n     if (op == \">\")\n     {\n         var expr = Expression.Lambda>(\n             Expression.MakeBinary(ExpressionType.GreaterThan\n                                 , Expression.PropertyOrField(p1, field)\n                                 , Expression.Convert(p2, typeof(T))), p1, p2);\n         var f = expr.Compile();\n         return f(data, value);\n      <span style=\"background-color: inherit; font-family: monospace; font-size: inherit;\">} <\/span>\n      <span style=\"background-color: inherit; font-family: monospace; font-size: inherit;\">return false;<\/span>\n }<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Code DOM CSharpScript<\/h2>\n\n\n\n<p>Another way to approach the same problem is to generate C# code that we can compile and run .We&#8217;d need <code>Microsoft.CodeAnalysis.CSharp.Scripting<\/code> package for this to work:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"csharp\" class=\"language-csharp\">bool BuildScript(DataThing data, string field, string op, T value)\n {\n     var code = $\"return {field} {op} {value};\";\n     var script = CSharpScript.Create(code, globalsType: typeof(DataThing), options: ScriptOptions.Default);\n     var scriptRunner = script.CreateDelegate();\n     return scriptRunner(data).Result;\n }<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">.NET 5 Code Generator<\/h2>\n\n\n\n<p>This is a new <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/introducing-c-source-generators\/\">.NET 5 feature<\/a>, that allows us to plug into compilation process and generate classes as we see fit. For example we&#8217;d generate extension methods that would all return correct values from <code>DataThing<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"csharp\" class=\"language-csharp\">[Generator] \/\/ see https:\/\/github.com\/dotnet\/roslyn\/blob\/main\/docs\/features\/source-generators.cookbook.md for even more cool stuff\n class AccessorGenerator: ISourceGenerator {\n     public void Execute(GeneratorExecutionContext context) {\n       var syntaxReceiver = (CustomSyntaxReceiver) context.SyntaxReceiver;\n       ClassDeclarationSyntax userClass = syntaxReceiver.ClassToAugment;\n       SourceText sourceText = SourceText.From($ @ \"\n         public static class DataThingExtensions {\n           { \n           \/\/ This is where we'd reflect over type members and generate code dynamically. Following code is oversimplification\n             public static string GetValue&lt;string>(this DataThing d) => d.Name;\n             public static string GetValue&lt;float>(this DataThing d) => d.Value;\n             public static string GetValue&lt;int>(this DataThing d) => d.Count;\n           }\n         }\n         \", Encoding.UTF8);\n         context.AddSource(\"DataThingExtensions.cs\", sourceText);\n       }\n       public void Initialize(GeneratorInitializationContext context) {\n         context.RegisterForSyntaxNotifications(() => new CustomSyntaxReceiver());\n       }\n       class CustomSyntaxReceiver: ISyntaxReceiver {\n         public ClassDeclarationSyntax ClassToAugment {\n           get;\n           private set;\n         }\n         public void OnVisitSyntaxNode(SyntaxNode syntaxNode) {\n           \/\/ Business logic to decide what we're interested in goes here\n           if (syntaxNode is ClassDeclarationSyntax cds &amp;&amp;\n             cds.Identifier.ValueText == \"DataThing\") {\n             ClassToAugment = cds;\n           }\n         }\n       }\n     }<\/code><\/pre>\n\n\n\n<p>Running this should be as easy as calling extension methods on the class instance: <code>data.GreaterThan(15f).Dump();<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Every now and then we get asked if there&#8217;s an easy way to parse user input into filter conditions. Say, for example, we have a viewmodel of type DataThing: From here we&#8217;d like to check if a given property of this class satisfies a certain condition. For example we&#8217;ll look at &#8220;Value is greater than &hellip; <a href=\"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Approaches to handling simple expressions in C#&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":418,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[11],"tags":[12,53],"class_list":["post-692","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev","tag-c","tag-roslyn"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Approaches to handling simple expressions in C# - Timur and associates<\/title>\n<meta name=\"description\" content=\"In this post we&#039;ll discuss a few ways to handle dynamic expressions with C#. We&#039;ll look at LINQ expression trees and .NET 5 code generation.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Approaches to handling simple expressions in C# - Timur and associates\" \/>\n<meta property=\"og:description\" content=\"In this post we&#039;ll discuss a few ways to handle dynamic expressions with C#. We&#039;ll look at LINQ expression trees and .NET 5 code generation.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/\" \/>\n<meta property=\"og:site_name\" content=\"Timur and associates\" \/>\n<meta property=\"article:published_time\" content=\"2021-01-27T04:40:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-08-18T12:24:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.wiseowls.co.nz\/wp-content\/uploads\/2020\/03\/technology-computer-desktop-programming-113850_cr-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"600\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"timur\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@TimurKh\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/\"},\"author\":{\"name\":\"timur\",\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/#\\\/schema\\\/person\\\/34d0ed30d573b5bc317ea990bd2e0c59\"},\"headline\":\"Approaches to handling simple expressions in C#\",\"datePublished\":\"2021-01-27T04:40:00+00:00\",\"dateModified\":\"2021-08-18T12:24:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/\"},\"wordCount\":227,\"image\":{\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/wp-content\\\/uploads\\\/2020\\\/03\\\/technology-computer-desktop-programming-113850_cr-scaled.jpg\",\"keywords\":[\"c#\",\"roslyn\"],\"articleSection\":[\"Development\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/\",\"url\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/\",\"name\":\"Approaches to handling simple expressions in C# - Timur and associates\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/wp-content\\\/uploads\\\/2020\\\/03\\\/technology-computer-desktop-programming-113850_cr-scaled.jpg\",\"datePublished\":\"2021-01-27T04:40:00+00:00\",\"dateModified\":\"2021-08-18T12:24:16+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/#\\\/schema\\\/person\\\/34d0ed30d573b5bc317ea990bd2e0c59\"},\"description\":\"In this post we'll discuss a few ways to handle dynamic expressions with C#. We'll look at LINQ expression trees and .NET 5 code generation.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/#primaryimage\",\"url\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/wp-content\\\/uploads\\\/2020\\\/03\\\/technology-computer-desktop-programming-113850_cr-scaled.jpg\",\"contentUrl\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/wp-content\\\/uploads\\\/2020\\\/03\\\/technology-computer-desktop-programming-113850_cr-scaled.jpg\",\"width\":2560,\"height\":600},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/index.php\\\/2021\\\/01\\\/27\\\/approaches-to-handling-simple-expressions-in-c\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Approaches to handling simple expressions in C#\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/#website\",\"url\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/\",\"name\":\"Timur and associates\",\"description\":\"Notes of an IT contractor\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/blog.wiseowls.co.nz\\\/#\\\/schema\\\/person\\\/34d0ed30d573b5bc317ea990bd2e0c59\",\"name\":\"timur\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/23d55e17d4f0990ee4d12bc6e5dcfb58a292934efd62a185756876379e780b16?s=96&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/23d55e17d4f0990ee4d12bc6e5dcfb58a292934efd62a185756876379e780b16?s=96&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/23d55e17d4f0990ee4d12bc6e5dcfb58a292934efd62a185756876379e780b16?s=96&r=pg\",\"caption\":\"timur\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/TimurKh\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Approaches to handling simple expressions in C# - Timur and associates","description":"In this post we'll discuss a few ways to handle dynamic expressions with C#. We'll look at LINQ expression trees and .NET 5 code generation.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/","og_locale":"en_US","og_type":"article","og_title":"Approaches to handling simple expressions in C# - Timur and associates","og_description":"In this post we'll discuss a few ways to handle dynamic expressions with C#. We'll look at LINQ expression trees and .NET 5 code generation.","og_url":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/","og_site_name":"Timur and associates","article_published_time":"2021-01-27T04:40:00+00:00","article_modified_time":"2021-08-18T12:24:16+00:00","og_image":[{"width":2560,"height":600,"url":"https:\/\/blog.wiseowls.co.nz\/wp-content\/uploads\/2020\/03\/technology-computer-desktop-programming-113850_cr-scaled.jpg","type":"image\/jpeg"}],"author":"timur","twitter_card":"summary_large_image","twitter_creator":"@TimurKh","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/#article","isPartOf":{"@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/"},"author":{"name":"timur","@id":"https:\/\/blog.wiseowls.co.nz\/#\/schema\/person\/34d0ed30d573b5bc317ea990bd2e0c59"},"headline":"Approaches to handling simple expressions in C#","datePublished":"2021-01-27T04:40:00+00:00","dateModified":"2021-08-18T12:24:16+00:00","mainEntityOfPage":{"@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/"},"wordCount":227,"image":{"@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/#primaryimage"},"thumbnailUrl":"https:\/\/blog.wiseowls.co.nz\/wp-content\/uploads\/2020\/03\/technology-computer-desktop-programming-113850_cr-scaled.jpg","keywords":["c#","roslyn"],"articleSection":["Development"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/","url":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/","name":"Approaches to handling simple expressions in C# - Timur and associates","isPartOf":{"@id":"https:\/\/blog.wiseowls.co.nz\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/#primaryimage"},"image":{"@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/#primaryimage"},"thumbnailUrl":"https:\/\/blog.wiseowls.co.nz\/wp-content\/uploads\/2020\/03\/technology-computer-desktop-programming-113850_cr-scaled.jpg","datePublished":"2021-01-27T04:40:00+00:00","dateModified":"2021-08-18T12:24:16+00:00","author":{"@id":"https:\/\/blog.wiseowls.co.nz\/#\/schema\/person\/34d0ed30d573b5bc317ea990bd2e0c59"},"description":"In this post we'll discuss a few ways to handle dynamic expressions with C#. We'll look at LINQ expression trees and .NET 5 code generation.","breadcrumb":{"@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/#primaryimage","url":"https:\/\/blog.wiseowls.co.nz\/wp-content\/uploads\/2020\/03\/technology-computer-desktop-programming-113850_cr-scaled.jpg","contentUrl":"https:\/\/blog.wiseowls.co.nz\/wp-content\/uploads\/2020\/03\/technology-computer-desktop-programming-113850_cr-scaled.jpg","width":2560,"height":600},{"@type":"BreadcrumbList","@id":"https:\/\/blog.wiseowls.co.nz\/index.php\/2021\/01\/27\/approaches-to-handling-simple-expressions-in-c\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.wiseowls.co.nz\/"},{"@type":"ListItem","position":2,"name":"Approaches to handling simple expressions in C#"}]},{"@type":"WebSite","@id":"https:\/\/blog.wiseowls.co.nz\/#website","url":"https:\/\/blog.wiseowls.co.nz\/","name":"Timur and associates","description":"Notes of an IT contractor","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.wiseowls.co.nz\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.wiseowls.co.nz\/#\/schema\/person\/34d0ed30d573b5bc317ea990bd2e0c59","name":"timur","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/23d55e17d4f0990ee4d12bc6e5dcfb58a292934efd62a185756876379e780b16?s=96&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/23d55e17d4f0990ee4d12bc6e5dcfb58a292934efd62a185756876379e780b16?s=96&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/23d55e17d4f0990ee4d12bc6e5dcfb58a292934efd62a185756876379e780b16?s=96&r=pg","caption":"timur"},"sameAs":["https:\/\/x.com\/TimurKh"]}]}},"_links":{"self":[{"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/posts\/692","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/comments?post=692"}],"version-history":[{"count":3,"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/posts\/692\/revisions"}],"predecessor-version":[{"id":883,"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/posts\/692\/revisions\/883"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/media\/418"}],"wp:attachment":[{"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/media?parent=692"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/categories?post=692"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.wiseowls.co.nz\/index.php\/wp-json\/wp\/v2\/tags?post=692"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}