{"id":3947,"date":"2025-12-19T10:00:00","date_gmt":"2025-12-19T15:00:00","guid":{"rendered":"https:\/\/www.mymiller.name\/wordpress\/?p=3947"},"modified":"2025-12-17T10:23:10","modified_gmt":"2025-12-17T15:23:10","slug":"goodbye-boilerplate-mastering-declarative-http-clients-in-spring-boot","status":"publish","type":"post","link":"https:\/\/www.mymiller.name\/wordpress\/spring\/spring4\/goodbye-boilerplate-mastering-declarative-http-clients-in-spring-boot\/","title":{"rendered":"Goodbye Boilerplate: Mastering Declarative HTTP Clients in Spring Boot"},"content":{"rendered":"\n<p>For years, calling remote REST APIs in Spring Boot meant one of two things: wrestling with the aging, blocking <code>RestTemplate<\/code>, or writing verbose, reactive boilerplate with <code>WebClient<\/code>.<\/p>\n\n\n\n<p>While libraries like Spring Cloud Feign offered a cleaner, declarative approach, they required extra dependencies and configuration.<\/p>\n\n\n\n<p>With the arrival of Spring Framework 6 and Spring Boot 3, declarative HTTP interfaces are now a native part of the core framework. It\u2019s time to modernize how your microservices talk to each other.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Goal<\/h2>\n\n\n\n<p>We are going to build a simple Spring Boot application that consumes a third-party API. We will use the classic <a href=\"https:\/\/jsonplaceholder.typicode.com\/\">JSONPlaceholder<\/a> API to fetch &#8220;Todo&#8221; items.<\/p>\n\n\n\n<p><strong>The Remote Endpoint:<\/strong> <code>https:\/\/jsonplaceholder.typicode.com\/todos<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>To follow along, you need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Java 17 or higher.<\/li>\n\n\n\n<li>Spring Boot 3.1 or higher (we will use 3.2 for the latest features).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Project Setup and Dependencies<\/h2>\n\n\n\n<p>Create a new Spring Boot project. You only need one main dependency.<\/p>\n\n\n\n<p>Even though the new interfaces look synchronous, they were originally powered by reactive infrastructure (<code>WebClient<\/code>) under the hood in Spring Boot 3.0\/3.1.<\/p>\n\n\n\n<p><strong>Gradle (build.gradle.kts):<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dependencies {\n    implementation(\"org.springframework.boot:spring-boot-starter-webflux\")\n}\n<\/code><\/pre>\n\n\n\n<p><em>(Note: If you are using Spring Boot 3.2+, it is possible to use <code>spring-boot-starter-web<\/code> and the new <code>RestClient<\/code> backend to avoid reactive dependencies entirely, but <code>webflux<\/code> remains the most versatile option across Spring Boot 3.x).<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Define the Domain Model<\/h2>\n\n\n\n<p>We need a Java object that maps to the JSON response from the remote service. Java Records are perfect for this.<\/p>\n\n\n\n<p>The JSON looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"userId\": 1,\n  \"id\": 1,\n  \"title\": \"delectus aut autem\",\n  \"completed\": false\n}\n<\/code><\/pre>\n\n\n\n<p><strong>Todo.java:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.demo.model;\n\npublic record Todo(Integer id, Integer userId, String title, Boolean completed) {\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: The Declarative Interface (The Magic)<\/h2>\n\n\n\n<p>This is where the new feature shines. Instead of writing a service class that injects <code>WebClient<\/code> and manually constructs a request, we just define an interface.<\/p>\n\n\n\n<p>We use the new <code>@HttpExchange<\/code> annotations (part of <code>org.springframework.web.service.annotation<\/code>).<\/p>\n\n\n\n<p><strong>TodoClient.java:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.demo.client;\n\nimport com.example.demo.model.Todo;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.service.annotation.GetExchange;\nimport org.springframework.web.service.annotation.HttpExchange;\nimport org.springframework.web.service.annotation.PostExchange;\n\nimport java.util.List;\n\n\/\/ 1. Define base path for all methods in this interface\n@HttpExchange(\"\/todos\")\npublic interface TodoClient {\n\n    \/\/ 2. Maps to GET \/todos\n    @GetExchange\n    List&lt;Todo&gt; getAllTodos();\n\n    \/\/ 3. Maps to GET \/todos\/{id} using standard Spring @PathVariable\n    @GetExchange(\"\/{id}\")\n    Todo getTodoById(@PathVariable(\"id\") Integer id);\n\n    \/\/ 4. Example of a POST operation\n    @PostExchange\n    Todo createTodo(@RequestBody Todo todo);\n}\n<\/code><\/pre>\n\n\n\n<p>Notice how clean this is. It looks exactly like a Spring MVC Controller definition, but it&#8217;s used for <em>client-side<\/em> calls.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Configuration (Wiring it up)<\/h2>\n\n\n\n<p>This is the most crucial step. Spring Boot knows about the interface, but it doesn&#8217;t know <em>where<\/em> the actual server lies (the base URL: <code>https:\/\/jsonplaceholder.typicode.com<\/code>).<\/p>\n\n\n\n<p>We need to create a configuration bean that tells Spring how to generate the concrete implementation of our <code>TodoClient<\/code> interface via the <code>HttpServiceProxyFactory<\/code>.<\/p>\n\n\n\n<p><strong>ClientConfig.java:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.demo.config;\n\nimport com.example.demo.client.TodoClient;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.reactive.function.client.support.WebClientAdapter;\nimport org.springframework.web.service.invoker.HttpServiceProxyFactory;\n\n@Configuration\npublic class ClientConfig {\n\n    @Bean\n    TodoClient todoClient(WebClient.Builder builder) {\n        \/\/ 1. Create the underlying WebClient with the base URL\n        WebClient webClient = builder\n                .baseUrl(\"&#91;https:\/\/jsonplaceholder.typicode.com](https:\/\/jsonplaceholder.typicode.com)\")\n                \/\/ You could add default headers here, e.g., for auth\n                \/\/ .defaultHeader(\"Authorization\", \"Bearer my-token\")\n                .build();\n\n        \/\/ 2. Create an adapter that bridges WebClient to the HTTP Service machinery\n        WebClientAdapter adapter = WebClientAdapter.create(webClient);\n        \n        \/\/ 3. Create the factory\n        HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();\n\n        \/\/ 4. Ask the factory to create the actual implementation of your interface\n        return factory.createClient(TodoClient.class);\n    }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udca1 Pro-Tip for Spring Boot 3.2+ Users<\/h3>\n\n\n\n<p>If you are on the absolute latest version (Spring Boot 3.2) and you are in a traditional Servlet application (not reactive), you can use the new <code>RestClient<\/code> instead of <code>WebClient<\/code> for the backend.<\/p>\n\n\n\n<p>You would swap lines 2 and 3 above for this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Requires Spring Boot 3.2+ and spring-boot-starter-web\nRestClient restClient = RestClient.builder().baseUrl(\"&#91;https:\/\/jsonplaceholder.typicode.com](https:\/\/jsonplaceholder.typicode.com)\").build();\nRestClientAdapter adapter = RestClientAdapter.create(restClient);\n\/\/ ... rest of factory setup is same\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Usage<\/h2>\n\n\n\n<p>Now that we have configured the <code>@Bean<\/code>, we can inject <code>TodoClient<\/code> anywhere in our application just like any other service.<\/p>\n\n\n\n<p><strong>DemoApplication.java:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.demo;\n\nimport com.example.demo.client.TodoClient;\nimport com.example.demo.model.Todo;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\nimport java.util.List;\n\n@SpringBootApplication\npublic class DemoApplication {\n\n    public static void main(String&#91;] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n    @Bean\n    CommandLineRunner run(TodoClient todoClient) {\n        return args -&gt; {\n            System.out.println(\"--- Starting HTTP Interface Demo ---\");\n\n            \/\/ 1. Fetch all\n            System.out.println(\"Fetching all todos...\");\n            List&lt;Todo&gt; allTodos = todoClient.getAllTodos();\n            System.out.println(\"Found \" + allTodos.size() + \" todos.\");\n            if (!allTodos.isEmpty()) {\n                System.out.println(\"First todo title: \" + allTodos.get(0).title());\n            }\n\n            \/\/ 2. Fetch one\n            System.out.println(\"\\nFetching Todo #5...\");\n            Todo todoFive = todoClient.getTodoById(5);\n            System.out.println(\"Todo #5: \" + todoFive);\n\n            \/\/ 3. Create (Mock)\n            System.out.println(\"\\nCreating a new Todo...\");\n            Todo newTodo = new Todo(null, 101, \"Learn Spring Boot 3 HTTP Interfaces\", false);\n            Todo createdTodo = todoClient.createTodo(newTodo);\n            \/\/ Note: JSONPlaceholder will return HTTP 201 but always return id 201.\n            System.out.println(\"Created Todo response: \" + createdTodo);\n\n            System.out.println(\"--- Demo Finished ---\");\n        };\n    }\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Why is this better?<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Readability:<\/strong> Your client code is now just an interface definition. It&#8217;s incredibly easy to read and understand what API calls your application is making.<\/li>\n\n\n\n<li><strong>Maintainability:<\/strong> Changing an endpoint path or a parameter happens in one annotation, not buried deep in service logic strings.<\/li>\n\n\n\n<li><strong>Standardization:<\/strong> It uses standard Spring MVC annotations (<code>@PathVariable<\/code>, <code>@RequestBody<\/code>, <code>@RequestParam<\/code>) that you already know from building server-side APIs.<\/li>\n\n\n\n<li><strong>Testability:<\/strong> Because <code>TodoClient<\/code> is just an interface, mock testing your services that <em>depend<\/em> on this client becomes incredibly easy using Mockito.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>For years, calling remote REST APIs in Spring Boot meant one of two things: wrestling with the aging, blocking RestTemplate, or writing verbose, reactive boilerplate with WebClient. While libraries like Spring Cloud Feign offered a cleaner, declarative approach, they required extra dependencies and configuration. With the arrival of Spring Framework 6 and Spring Boot 3, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3948,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[483],"tags":[486,484],"series":[],"class_list":["post-3947","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-spring4","tag-apring","tag-spring4"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/putty-3678638_1280.avif","jetpack-related-posts":[{"id":3944,"url":"https:\/\/www.mymiller.name\/wordpress\/spring\/spring4\/goodbye-resilience4j-native-fault-tolerance-in-spring-boot-4\/","url_meta":{"origin":3947,"position":0},"title":"Goodbye Resilience4j? Native Fault Tolerance in Spring Boot 4","author":"Jeffery Miller","date":"December 18, 2025","format":false,"excerpt":"For years, the standard advice for building resilient Spring Boot microservices was simple: add Resilience4j. It became the Swiss Army knife for circuit breakers, rate limiters, and retries. However, with the release of Spring Boot 4, the landscape has shifted. The framework now promotes a \"batteries-included\" philosophy for fault tolerance.\u2026","rel":"","context":"In &quot;Spring4&quot;","block_context":{"text":"Spring4","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring\/spring4\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/iduino-uno-r3b-1699990_1280.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/iduino-uno-r3b-1699990_1280.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/iduino-uno-r3b-1699990_1280.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/iduino-uno-r3b-1699990_1280.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/iduino-uno-r3b-1699990_1280.avif 3x"},"classes":[]},{"id":3912,"url":"https:\/\/www.mymiller.name\/wordpress\/uncategorized\/spring-boot-4-0-whats-next-for-the-modern-java-architect\/","url_meta":{"origin":3947,"position":1},"title":"Spring Boot 4.0: What&#8217;s Next for the Modern Java Architect?","author":"Jeffery Miller","date":"September 24, 2025","format":false,"excerpt":"A Forward-Looking Comparison of Spring Boot 3.x and 4.0 Staying on top of the rapidly evolving Java ecosystem is paramount for any software architect. The shift from Spring Boot 2.x to 3.x brought significant changes, notably the move to Jakarta EE. Now, with the horizon of Spring Boot 4.0 and\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif 3x"},"classes":[]},{"id":3940,"url":"https:\/\/www.mymiller.name\/wordpress\/spring\/spring4\/spring-boot-4-mastering-rest-api-versioning-with-apiversion\/","url_meta":{"origin":3947,"position":2},"title":"Spring Boot 4: Mastering REST API Versioning with @ApiVersion","author":"Jeffery Miller","date":"December 17, 2025","format":false,"excerpt":"As software architects, we often face the challenge of evolving our APIs without breaking the contracts relied upon by existing clients. For years, Spring developers had to rely on manual workarounds\u2014custom RequestCondition implementations, path pattern matching, or third-party libraries\u2014to handle versioning. With the release of Spring Boot 4 (built on\u2026","rel":"","context":"In &quot;Spring4&quot;","block_context":{"text":"Spring4","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring\/spring4\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/brain-2029391_1280.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/brain-2029391_1280.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/brain-2029391_1280.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/brain-2029391_1280.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/brain-2029391_1280.avif 3x"},"classes":[]},{"id":3438,"url":"https:\/\/www.mymiller.name\/wordpress\/spring\/architecting-with-spring-and-spring-cloud\/","url_meta":{"origin":3947,"position":3},"title":"Architecting with Spring and Spring Cloud","author":"Jeffery Miller","date":"December 24, 2025","format":false,"excerpt":"Building a Multi-Service Architecture with Spring 3.1.x and Spring Cloud: Unlocking the Power of Microservices In the ever-evolving landscape of software development, microservices have emerged as a powerful architectural paradigm, enabling organizations to build scalable, resilient, and agile applications. Spring, a widely adopted Java framework, provides a comprehensive suite of\u2026","rel":"","context":"In &quot;Spring&quot;","block_context":{"text":"Spring","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2023\/11\/field-5236879_640.jpg?fit=640%2C360&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2023\/11\/field-5236879_640.jpg?fit=640%2C360&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2023\/11\/field-5236879_640.jpg?fit=640%2C360&ssl=1&resize=525%2C300 1.5x"},"classes":[]},{"id":3961,"url":"https:\/\/www.mymiller.name\/wordpress\/spring\/spring4\/architecting-spring-boot-4-with-official-spring-grpc-support\/","url_meta":{"origin":3947,"position":4},"title":"Architecting Spring Boot 4 with Official Spring gRPC Support","author":"Jeffery Miller","date":"January 15, 2026","format":false,"excerpt":"For years, the Spring community relied on excellent third-party starters (like net.devh) to bridge the gap between Spring Boot and gRPC. With the evolution of Spring Boot 4 and the official Spring gRPC project, we now have native support that aligns perfectly with Spring's dependency injection, observability, and configuration models.\u2026","rel":"","context":"In &quot;Spring4&quot;","block_context":{"text":"Spring4","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring\/spring4\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/01\/Gemini_Generated_Image_3yqio33yqio33yqi.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/01\/Gemini_Generated_Image_3yqio33yqio33yqi.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/01\/Gemini_Generated_Image_3yqio33yqio33yqi.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/01\/Gemini_Generated_Image_3yqio33yqio33yqi.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/01\/Gemini_Generated_Image_3yqio33yqio33yqi.avif 3x"},"classes":[]},{"id":3951,"url":"https:\/\/www.mymiller.name\/wordpress\/java\/scaling-streams-mastering-virtual-threads-in-spring-boot-4-and-java-25\/","url_meta":{"origin":3947,"position":5},"title":"Scaling Streams: Mastering Virtual Threads in Spring Boot 4 and Java 25","author":"Jeffery Miller","date":"December 22, 2025","format":false,"excerpt":"As a software architect, I\u2019ve seen the industry shift from heavy platform threads to reactive streams, and finally to the \"best of both worlds\": Virtual Threads. With the recent release of Spring Boot 4.0 and Java 25 (LTS), Project Loom's innovations have officially become the bedrock of high-concurrency enterprise Java.\u2026","rel":"","context":"In &quot;JAVA&quot;","block_context":{"text":"JAVA","link":"https:\/\/www.mymiller.name\/wordpress\/category\/java\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/12\/Gemini_Generated_Image_wqijejwqijejwqij-scaled.avif 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3947","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/comments?post=3947"}],"version-history":[{"count":1,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3947\/revisions"}],"predecessor-version":[{"id":3949,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3947\/revisions\/3949"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media\/3948"}],"wp:attachment":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media?parent=3947"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/categories?post=3947"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/tags?post=3947"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/series?post=3947"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}