{"id":3530,"date":"2026-04-20T09:29:17","date_gmt":"2026-04-20T13:29:17","guid":{"rendered":"https:\/\/www.mymiller.name\/wordpress\/?p=3530"},"modified":"2026-04-20T09:29:17","modified_gmt":"2026-04-20T13:29:17","slug":"spring-jpa-auditing-track-data-changes","status":"publish","type":"post","link":"https:\/\/www.mymiller.name\/wordpress\/spring_databases\/spring-jpa-auditing-track-data-changes\/","title":{"rendered":"Spring JPA Auditing: Track Data Changes"},"content":{"rendered":"\n<p>In the dynamic world of software development, understanding the complete history of your data is crucial. Who made a change? When did it occur? Who viewed the data? Spring JPA Auditing, combined with custom solutions, offers a comprehensive way to answer these questions, acting as a time machine for your database records.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is JPA Auditing?<\/h2>\n\n\n\n<p>The Java Persistence API (JPA) is the standard for object-relational mapping in Java. While JPA itself doesn&#8217;t have a built-in auditing mechanism, Spring Data JPA, a powerful extension, seamlessly fills this gap. JPA Auditing allows you to automatically track:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Creation Information:<\/strong> Who created a record and when. <\/li>\n\n\n\n<li><strong>Modification Information:<\/strong> Who last updated a record and when.<\/li>\n\n\n\n<li><strong>Accessed Information:<\/strong> Who accessed what data.<\/li>\n<\/ul>\n\n\n\n<p>The beauty of this is that it&#8217;s all done behind the scenes, requiring minimal developer intervention.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why Audit Your Data?<\/h2>\n\n\n\n<p>Auditing isn&#8217;t just about compliance or security, though those are crucial aspects. Consider these benefits:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Troubleshooting:<\/strong> Quickly pinpoint the origin of data errors. <\/li>\n\n\n\n<li><strong>Data Recovery:<\/strong> Roll back to previous states in case of accidental modifications. <\/li>\n\n\n\n<li><strong>Transparency:<\/strong> Understand who&#8217;s interacting with your data and how. <\/li>\n\n\n\n<li><strong>Regulatory Compliance:<\/strong> Fulfill requirements for data retention and accountability. <\/li>\n\n\n\n<li><strong>Security and Anomaly Detection:<\/strong> Identify unusual access patterns.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Spring JPA Auditing in Action<\/h2>\n\n\n\n<p>Let&#8217;s dive into how you can harness the power of Spring JPA Auditing:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Enable Auditing:<\/h3>\n\n\n\n<p>In your Spring Boot application&#8217;s main configuration class, add the <code>@EnableJpaAuditing<\/code> annotation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Configuration\n@EnableJpaAuditing\npublic class AppConfig {\n    \/\/ ... your other configurations\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Annotate Your Entities:<\/h3>\n\n\n\n<p>Use the following annotations in your entity classes to mark fields for auditing:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>@CreatedBy<\/code>: Captures the creator&#8217;s username or ID. <\/li>\n\n\n\n<li><code>@CreatedDate<\/code>: Records the creation timestamp. <\/li>\n\n\n\n<li><code>@LastModifiedBy<\/code>: Tracks the last modifier&#8217;s username or ID. <\/li>\n\n\n\n<li><code>@LastModifiedDate<\/code>: Stores the last modification timestamp.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>@Entity\npublic class Product {\n    \/\/ ... other fields\n\n    @CreatedBy\n    private String createdBy;\n\n    @CreatedDate\n    private LocalDateTime createdDate;\n\n    @LastModifiedBy\n    private String lastModifiedBy;\n\n    @LastModifiedDate\n    private LocalDateTime lastModifiedDate;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">AuditorAware (Optional):<\/h3>\n\n\n\n<p>To customize how you capture the current user (e.g., from Spring Security), implement the <code>AuditorAware<\/code> interface:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Component\npublic class AuditorAwareImpl implements AuditorAware&lt;String> {\n    @Override\n    public Optional&lt;String> getCurrentAuditor() {\n        \/\/ ... your logic to fetch the current user's username or ID\n    }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Storing Audit Information in a Separate Table with EntityListeners<\/h3>\n\n\n\n<p>While Spring JPA Auditing conveniently stores audit information directly within the audited entities, a separate audit log table offers more flexibility and better reporting capabilities.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Create an Audit Log Entity:<\/h4>\n\n\n\n<p>Design an entity to hold the audit log entries:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Entity\npublic class AuditLog {\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    private String entityType; \/\/ e.g., \"Product\"\n    private Long entityId;\n    private String action;     \/\/ e.g., \"CREATE\", \"UPDATE\", \"DELETE\", \"READ\"\n    private String modifiedBy; \n    private LocalDateTime modifiedDate;\n    \/\/ ... other relevant fields (old values, new values)\n}\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Implement an EntityListener:<\/h4>\n\n\n\n<p>Create an <code>EntityListener<\/code> that intercepts entity lifecycle events and saves audit log entries:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class AuditLogListener {\n    @PostPersist\n    public void postPersist(Object entity) {\n        saveAuditLog(entity, \"CREATE\");\n    }\n\n    @PostUpdate\n    public void postUpdate(Object entity) {\n        saveAuditLog(entity, \"UPDATE\");\n    }\n\n    @PostRemove\n    public void postRemove(Object entity) {\n        saveAuditLog(entity, \"DELETE\");\n    }\n\n    \/\/ ... (saveAuditLog method implementation)\n}\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Register the EntityListener:<\/h4>\n\n\n\n<p>Annotate the entities you want to audit with <code>@EntityListeners<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Entity\n@EntityListeners(AuditLogListener.class)\npublic class Product { \/* ... *\/ }\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Example: Audit Log Table<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE audit_log (\n    id BIGSERIAL PRIMARY KEY,\n    entity_type VARCHAR(255) NOT NULL,\n    entity_id BIGINT NOT NULL,\n    action VARCHAR(255) NOT NULL,\n    user_id VARCHAR(255) NOT NULL,\n    timestamp TIMESTAMP NOT NULL\n);\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Tracking Data Access (Read Events) with an Audit Table<\/h3>\n\n\n\n<p>To track when data is accessed (read), a common approach is to use an audit table in combination with aspect-oriented programming (AOP):<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Create a ReadLog Entity:<\/h3>\n\n\n\n<p>Design an entity to hold read access information:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Entity\npublic class ReadLog {\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    private String entityType; \/\/ e.g., \"Product\"\n    private Long entityId;\n    private String accessedBy;\n    private LocalDateTime accessedDate;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Implement an Aspect:<\/h3>\n\n\n\n<p>Use AOP to intercept service or repository method calls that retrieve data and save an entry in the <code>ReadLog<\/code> table:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Aspect\n@Component\npublic class ReadLogAspect {\n    @Autowired\n    private ReadLogRepository readLogRepository;\n\n    @AfterReturning(pointcut = \"execution(* com.example.repository.*.find*(..))\", returning = \"result\")\n    public void logDataAccess(JoinPoint joinPoint, Object result) {\n        if (result != null) {\n            \/\/ Extract entity information from the method arguments or result\n            String entityType = ...; \/\/ Get the entity type\n            Long entityId = ...;    \/\/ Get the entity ID\n\n            ReadLog readLog = new ReadLog();\n            readLog.setEntityType(entityType);\n            readLog.setEntityId(entityId);\n            readLog.setAccessedBy(getCurrentAuditor());\n            readLog.setAccessedDate(LocalDateTime.now());\n\n            readLogRepository.save(readLog);\n        }\n    }\n\n    \/\/ ... (Implementation of getCurrentAuditor similar to AuditorAware)\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Soft Deletes with JPA Auditing<\/h2>\n\n\n\n<p>Soft deletes are a way to mark a record as deleted without actually removing it from your database. This is particularly useful for data recovery and maintaining historical records. Here&#8217;s how to integrate soft deletes with JPA auditing:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Add a Deleted Flag:<\/h3>\n\n\n\n<p>Include a boolean field in your entity to indicate whether a record is soft deleted:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Entity\npublic class Product {\n    \/\/ ... other fields\n\n    private boolean deleted = false;  \/\/ Default to not deleted\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Modify Repository Methods:<\/h3>\n\n\n\n<p>Instead of using <code>delete()<\/code>, create custom repository methods that update the <code>deleted<\/code> flag and trigger auditing:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public interface ProductRepository extends JpaRepository&lt;Product, Long> {\n    @Modifying\n    @Query(\"UPDATE Product p SET p.deleted = true WHERE p.id = :id\")\n    void softDelete(@Param(\"id\") Long id);\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Querying:<\/h3>\n\n\n\n<p>Adjust your queries to filter out soft-deleted records by default:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>List&lt;Product> findProductsByDeletedFalse(); \/\/ Find non-deleted products\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In the dynamic world of software development, understanding the complete history of your data is crucial. Who made a change? When did it occur? Who viewed the data? Spring JPA Auditing, combined with custom solutions, offers a comprehensive way to answer these questions, acting as a time machine for your database records. What is JPA [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3531,"comment_status":"closed","ping_status":"closed","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":[435],"tags":[69,319],"series":[397],"class_list":["post-3530","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-spring_databases","tag-java-2","tag-spring","series-spring"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/image.png?fit=1792%2C1024&ssl=1","jetpack-related-posts":[{"id":3471,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_databases\/spring-jpa-auditing\/","url_meta":{"origin":3530,"position":0},"title":"Spring JPA Auditing","author":"Jeffery Miller","date":"December 24, 2025","format":false,"excerpt":"Simplifying Entity Auditing with Spring Data JPA Annotations Keeping track of who created and modified your entities is crucial for various purposes, including audit trails, security, and data lineage. Spring Data JPA offers a convenient and efficient way to achieve this through dedicated annotations: @CreatedBy, @LastModifiedBy, @CreatedDate, and @LastModifiedDate. Leveraging\u2026","rel":"","context":"In &quot;Spring Databases&quot;","block_context":{"text":"Spring Databases","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_databases\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/02\/audit-4190944_640.jpg?fit=640%2C377&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/02\/audit-4190944_640.jpg?fit=640%2C377&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/02\/audit-4190944_640.jpg?fit=640%2C377&ssl=1&resize=525%2C300 1.5x"},"classes":[]},{"id":3502,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_databases\/spring-data-jpa-for-dummies-persisting-data-like-a-pro\/","url_meta":{"origin":3530,"position":1},"title":"Spring Data JPA for Dummies: Persisting Data Like a Pro","author":"Jeffery Miller","date":"December 24, 2025","format":false,"excerpt":"Ever feel bogged down by writing tons of code just to interact with your database? If you're a Java developer working with relational databases, Spring Data JPA is your new best friend. This blog post will give you a beginner-friendly introduction to Spring Data JPA, showing you how to save\u2026","rel":"","context":"In &quot;Spring Databases&quot;","block_context":{"text":"Spring Databases","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_databases\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/binary-2904980_1280.jpg?fit=1200%2C674&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/binary-2904980_1280.jpg?fit=1200%2C674&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/binary-2904980_1280.jpg?fit=1200%2C674&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/binary-2904980_1280.jpg?fit=1200%2C674&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/binary-2904980_1280.jpg?fit=1200%2C674&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":3539,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_databases\/spring-data-cassandra-simplifying-java-development-with-apache-cassandra\/","url_meta":{"origin":3530,"position":2},"title":"Spring Data Cassandra: Simplifying Java Development with Apache Cassandra","author":"Jeffery Miller","date":"September 22, 2025","format":false,"excerpt":"Apache Cassandra is a powerful NoSQL database known for its scalability and high availability. Spring Data Cassandra seamlessly integrates Spring\u2019s familiar programming model with Cassandra, boosting developer productivity. Why Spring Data Cassandra? Simplified Configuration: Spring Boot auto-configuration minimizes manual setup. Object-Relational Mapping (ORM): Easily map Java objects to Cassandra tables.\u2026","rel":"","context":"In &quot;Spring Databases&quot;","block_context":{"text":"Spring Databases","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_databases\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/network-3396348_1280.jpg?fit=1200%2C720&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/network-3396348_1280.jpg?fit=1200%2C720&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/network-3396348_1280.jpg?fit=1200%2C720&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/network-3396348_1280.jpg?fit=1200%2C720&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/06\/network-3396348_1280.jpg?fit=1200%2C720&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":3692,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_aop\/tracking-method-access-in-spring-aop-security-and-jpa\/","url_meta":{"origin":3530,"position":3},"title":"Tracking Method Access in Spring: AOP, Security, and JPA","author":"Jeffery Miller","date":"November 20, 2025","format":false,"excerpt":"In the world of Spring applications, understanding how your methods are accessed can be crucial for various reasons like monitoring usage patterns, auditing security, or simply gathering insights into your application\u2019s behavior. Let\u2019s explore a powerful approach to track method access using Spring AOP (Aspect-Oriented Programming), Spring Security, and Spring\u2026","rel":"","context":"In &quot;Spring AOP&quot;","block_context":{"text":"Spring AOP","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_aop\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/money-3523131_1280-jpg.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/money-3523131_1280-jpg.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/money-3523131_1280-jpg.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/money-3523131_1280-jpg.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/09\/money-3523131_1280-jpg.avif 3x"},"classes":[]},{"id":3925,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_databases\/spring-data-jpa-java-records-the-ultimate-duo-for-clean-fast-query-projections\/","url_meta":{"origin":3530,"position":4},"title":"Spring Data JPA &#038; Java Records: The Ultimate Duo for Clean, Fast Query Projections","author":"Jeffery Miller","date":"November 20, 2025","format":false,"excerpt":"Architecting Efficient Data Access with Immutability As Spring developers, we spend a significant amount of time optimizing the path between the database and the client. One of the most common performance pitfalls is the over-fetching of data\u2014loading entire, complex JPA entities when all we need is a small subset of\u2026","rel":"","context":"In &quot;Spring Databases&quot;","block_context":{"text":"Spring Databases","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_databases\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/record-shop-9180482_1280.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/record-shop-9180482_1280.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/record-shop-9180482_1280.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/record-shop-9180482_1280.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/record-shop-9180482_1280.avif 3x"},"classes":[]},{"id":3820,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_rest\/effortless-api-creation-generating-crud-endpoints-with-spring-data-rest\/","url_meta":{"origin":3530,"position":5},"title":"Effortless API Creation: Generating CRUD Endpoints with Spring Data REST","author":"Jeffery Miller","date":"December 24, 2025","format":false,"excerpt":"Building RESTful APIs for your data can often feel like a repetitive task. Defining endpoints, handling HTTP methods (GET, POST, PUT, DELETE), serializing and deserializing data \u2013 it all adds up. But what if you could significantly reduce this boilerplate and focus on your core domain logic? Enter Spring Data\u2026","rel":"","context":"In &quot;Spring Rest&quot;","block_context":{"text":"Spring Rest","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_rest\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/05\/ai-generated-8041774_640.jpg?fit=640%2C479&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/05\/ai-generated-8041774_640.jpg?fit=640%2C479&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2024\/05\/ai-generated-8041774_640.jpg?fit=640%2C479&ssl=1&resize=525%2C300 1.5x"},"classes":[]}],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3530","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=3530"}],"version-history":[{"count":1,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3530\/revisions"}],"predecessor-version":[{"id":3532,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3530\/revisions\/3532"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media\/3531"}],"wp:attachment":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media?parent=3530"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/categories?post=3530"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/tags?post=3530"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/series?post=3530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}