{"id":830,"date":"2020-03-30T02:00:00","date_gmt":"2020-03-30T02:00:00","guid":{"rendered":"http:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-2-2ffb7e2550d5\/"},"modified":"2021-02-03T17:00:35","modified_gmt":"2021-02-03T17:00:35","slug":"simple-spring-boot-service-to-kubernetes-application-step-2-2ffb7e2550d5","status":"publish","type":"post","link":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-2-2ffb7e2550d5\/","title":{"rendered":"Create the Data Repository"},"content":{"rendered":"\n<p id=\"e74a\">In the previous step we initialized a spring boot project so that we can start development. In this step we\u2019re going to setup the persistence tier of the customer service.<\/p>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--p wp-block-heading\" id=\"6710\">Create the Data Repository<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"3c82\">I like to start with the data model at the persistence level and work up. Since the datastore is usually the \u2018foundation\u2019 of your applications it makes sense to me. We\u2019re going to use liquibase define a database \u2018contract\u2019, spring data jpa to create the data access layer and then H2 as an in-memory data store for testing.<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"99e3\">First, lets setup liquibase. In <code class=\"markup--code markup--p-code\">src\/main\/resources<\/code> create a directory structure for <code class=\"markup--code markup--p-code\">db\/changelog\/migrations<\/code>. First lets use liquibase to define a DDL for our database table. We\u2019re going to try and follow <a class=\"markup--anchor markup--p-anchor\" href=\"https:\/\/www.liquibase.org\/bestpractices.html\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/www.liquibase.org\/bestpractices.html\">liquibase best practices<\/a>. In <code class=\"markup--code markup--p-code\">src\/main\/resources\/db\/changelog\/migrations<\/code> create a file called <code class=\"markup--code markup--p-code\">0001-init-customer-table.yaml<\/code>. Inside that file lets define our customer table like this:<\/p>\n\n\n\n<pre id=\"3e16\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>databaseChangeLog:\n  - changeSet:\n      id: create-customer-table\n      author: brianrook\n      changes:\n        - createTable:\n            catalogName: medium\n            tableName: customer\n            columns:\n              - column:\n                  name: customer_id\n                  type: bigint\n                  constraints:\n                    primaryKey: true\n                    nullable: false\n              - column:\n                  name: first_name\n                  type: varchar(100)\n                  constraints:\n                    nullable: false\n              - column:\n                  name: last_name\n                  type: varchar(100)\n                  constraints:\n                    nullable: false\n              - column:\n                  name: phone_number\n                  type: varchar(20)\n              - column:\n                  name: email\n                  type: varchar(150)\n                  constraints:\n                    nullable: false\n              - column:\n                  name: create_timestamp\n                  type: timestamp\n                  constraints:\n                    nullable: false\n                  defaultValueComputed: CURRENT_TIMESTAMP\n              - column:\n                  name: modify_timestamp\n                  type: timestamp\n                  constraints:\n                    nullable: false\n                  defaultValueComputed: CURRENT_TIMESTAMP\n        - createSequence:\n            sequenceName: customer_seq\n            incrementBy: 1<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"297f\"><p>What we\u2019re doing here is defining the columns of our database table in a way that is compatible across DB platforms. Liquibase will read this configuration and generate the correct DB statements for your database. This \u2018contract\u2019 will work against H2, postgres, mysql, etc\u2026 without making any changes to your DDL. We\u2019re also defining a sequence that we\u2019ll use to manage the primary key on our table.<\/p><\/blockquote>\n\n\n\n<p class=\"graf graf--p graf-after--blockquote\" id=\"91fc\">However, we also need to define how these changelogs will be executed. We can do that via a changelog master. In <code class=\"markup--code markup--p-code\">src\/main\/resources\/db\/changelog<\/code> create a file called <code class=\"markup--code markup--p-code\">db.changelog-master.yaml<\/code> with this content:<\/p>\n\n\n\n<pre id=\"e56e\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>databaseChangeLog:\n  - includeAll:\n      path: db\/changelog\/migrations\/<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"0087\"><p>This will tell the application on startup to execute all of the changelogs in the defined directory. Since they\u2019re ordered by the file name convention, they will execute in the correct order. Additionally, on startup the application will detect which changelogs are currently applied to the database and will apply any changes that it detects have not been applied.<\/p><\/blockquote>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--blockquote wp-block-heading\" id=\"9729\">Create the&nbsp;Entity<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"d9f8\">Now lets create the data access object that will interact with the data repository. Create this package in <code class=\"markup--code markup--p-code\">src\/main\/java com.brianrook.medium.customer.dao.entity<\/code><\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"ab52\">In the <code class=\"markup--code markup--p-code\">entity <\/code>directory create your database entity <code class=\"markup--code markup--p-code\">CustomerEntity<\/code><\/p>\n\n\n\n<pre id=\"0415\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>package com.brianrook.medium.customer.dao.entity;\n\nimport lombok.Data;\n\nimport javax.persistence.*;\n\n@Data\n@Entity\n@Table(name = \"customer\")\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class CustomerEntity {\n    @Id\n    @SequenceGenerator(name = \"customer_seq\", sequenceName = \"customer_seq\", allocationSize = 1)\n    @GeneratedValue(strategy = GenerationType.<em class=\"markup--em markup--pre-em\">SEQUENCE<\/em>, generator = \"customer_seq\")\n    @Column(name = \"customer_id\")\n    private Long customerId;\n\n    @Column(name = \"first_name\")\n    private String firstName;\n    @Column(name = \"last_name\")\n    private String lastName;\n    @Column(name = \"phone_number\", nullable = false, unique = true)\n    private String phoneNumber;\n    @Column(name = \"email\", nullable = false, unique = true)\n    private String email;\n}<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"73d6\"><p>We\u2019re making a lot of use of Lombok here. If you\u2019re not familiar with it, it may be somewhat strange. Lombok uses the annotations to define code to generate at compile time. Here we\u2019re using it to generate getters, setters, toString, etc\u2026 which are all defined <a class=\"markup--anchor markup--blockquote-anchor\" href=\"https:\/\/projectlombok.org\/features\/Data\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/projectlombok.org\/features\/Data\">here<\/a>. I\u2019m also using <a class=\"markup--anchor markup--blockquote-anchor\" href=\"https:\/\/projectlombok.org\/features\/Builder\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/projectlombok.org\/features\/Builder\">builder <\/a>and some <a class=\"markup--anchor markup--blockquote-anchor\" href=\"https:\/\/projectlombok.org\/features\/constructor\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/projectlombok.org\/features\/constructor\">constructor<\/a> annotations. It keeps us from having to write a lot of boiler plate java code and speeds up our development time in addition to making the code very easy to read which also speeds up our development and debug time.<\/p><\/blockquote>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--blockquote wp-block-heading\" id=\"9243\">Create the&nbsp;DAO<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"b137\">In the <code class=\"markup--code markup--p-code\">com.brianrook.medium.customer.dao<\/code> directory create a java interface called <code class=\"markup--code markup--p-code\">CustomerDAO<\/code>. Add this content:<\/p>\n\n\n\n<pre id=\"ea2c\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>package com.brianrook.medium.customer.dao;\n\nimport com.brianrook.medium.customer.dao.entity.CustomerEntity;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface CustomerDAO extends CrudRepository&lt;CustomerEntity, Long&gt; {\n}<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"c03e\"><p>We\u2019re using spring data jpa to generate the boilerplate CRUD functions so we don\u2019t have to. We can also use this class to access the database directly, which we\u2019ll use in testing<\/p><\/blockquote>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--blockquote wp-block-heading\" id=\"c499\">Write the&nbsp;Test<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"0459\">Lets see if we can actually write into a table and access the data using the DAO we just wrote. In <code class=\"markup--code markup--p-code\">src\/test\/java<\/code> create a package called <code class=\"markup--code markup--p-code\">com.brianrook.medium.customer.dao<\/code>. Create a java test class called <code class=\"markup--code markup--p-code\">CustomerDAOTest<\/code> and add this content.<\/p>\n\n\n\n<pre id=\"faf1\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>package com.brianrook.medium.customer.dao;\n\nimport com.brianrook.medium.customer.dao.entity.CustomerEntity;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.util.Optional;\n\nimport static org.assertj.core.api.Assertions.<em class=\"markup--em markup--pre-em\">assertThat<\/em>;\n\n@ExtendWith(SpringExtension.class)\n@DataJpaTest\npublic class CustomerDAOTest {\n    @Autowired\n    private CustomerDAO customerDAO;\n\n    @Test\n    public void testSaveCustomer()\n    {\n        CustomerEntity testCustomer = CustomerEntity.<em class=\"markup--em markup--pre-em\">builder<\/em>()\n                .firstName(\"Brian\")\n                .lastName(\"Rook\")\n                .email(\"test.user@test.com\")\n                .phoneNumber(\"303-555-1212\")\n                .build();\n\n        customerDAO.save(testCustomer);\n\n        Optional&lt;CustomerEntity&gt; returnCustomer = customerDAO.findById(testCustomer.getCustomerId());\n\n<em class=\"markup--em markup--pre-em\">assertThat<\/em>(returnCustomer.isPresent()).isTrue();\n<em class=\"markup--em markup--pre-em\">assertThat<\/em>(returnCustomer.get()).isEqualTo(testCustomer);\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"591d\">If you run the test, you should bet a green check \/ success.<\/p>\n\n\n\n<p class=\"graf graf--p graf-after--p\" id=\"59e9\">We can look at the logs and see what just happened<\/p>\n\n\n\n<pre id=\"084e\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>2020-03-27 16:25:38.530  INFO &#91;,,,] 7636 --- &#91;           main] beddedDataSourceBeanFactoryPostProcessor : Replacing 'dataSource' DataSource bean with embedded version\n2020-03-27 16:25:38.863  INFO &#91;,,,] 7636 --- &#91;           main] o.s.j.d.e.EmbeddedDatabaseFactory        : Starting embedded database: url='jdbc:h2:mem:88a922a3-9a84-4153-8c73-085c38168e17;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"5d92\"><p>These lines are telling us that we\u2019re going to start a datasource and hook it up to in memory H2 database that spring starts up for us.<\/p><\/blockquote>\n\n\n\n<pre id=\"0056\" class=\"wp-block-code graf graf--pre graf-after--blockquote\"><code>2020-03-27 16:25:39.520  INFO &#91;,,,] 7636 --- &#91;           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect\nHibernate: drop table organizer if exists\nHibernate: drop sequence if exists customer_seq\nHibernate: create sequence customer_seq start with 1 increment by 1\nHibernate: create table organizer (customer_id bigint not null, email varchar(255) not null, first_name varchar(255), last_name varchar(255), phone_number varchar(255) not null, primary key (customer_id))\nHibernate: alter table organizer add constraint UK_s25r3nckqlux0klke4y3yb9u0 unique (email)\nHibernate: alter table organizer add constraint UK_81500y90b5jyslc733s8iisk unique (phone_number)<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"6d59\"><p>These lines are telling us that liquibase is using Hibernate to translate our liquibase changelog file into H2 dialect and then executing it.<\/p><\/blockquote>\n\n\n\n<pre id=\"e3d8\" class=\"wp-block-code graf graf--pre graf-after--blockquote\"><code>2020-03-27 16:25:40.362  INFO &#91;,,,] 7636 --- &#91;           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context ...\nHibernate: call next value for customer_seq\n2020-03-27 16:25:40.574  INFO &#91;,,,] 7636 --- &#91;           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: ...<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"1300\"><p>These lines are telling us that the unit test created a transaction for the duration of the test and then rolled it back when it finished. So we don\u2019t have to worry about stale test data contaminating our database during future test runs. This test is now idempotent and we can run it as much as we want and it will return the database to the original state.<\/p><\/blockquote>\n\n\n\n<h3 class=\"graf graf--h3 graf-after--blockquote wp-block-heading\" id=\"be1d\">Build and&nbsp;Commit<\/h3>\n\n\n\n<p class=\"graf graf--p graf-after--h3\" id=\"cff5\">Confirm our build still works:<\/p>\n\n\n\n<pre id=\"3ee3\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>mvn clean install<\/code><\/pre>\n\n\n\n<p class=\"graf graf--p graf-after--pre\" id=\"622d\">and if we have success we should commit<\/p>\n\n\n\n<pre id=\"1ca9\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>git checkout -b dao\ngit add .\ngit commit -m \"added database repository\"\ngit push --set-upstream origin dao<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote graf graf--blockquote graf-after--pre is-layout-flow wp-block-quote-is-layout-flow\" id=\"2efa\"><p>I\u2019m going to try and keep each step in its own branch. That way, if you\u2019re following along you can see each stage. I hated articles that had stages but the git repo was the \u2018final product\u2019 and it was difficult to see how the code or service evolved. I\u2019ll try and prevent that from happening here.<\/p><\/blockquote>\n\n\n\n<p class=\"graf graf--p graf-after--blockquote\" id=\"91d5\">I\u2019m also going to merge this branch back into master so that I can use it as a baseline for the next step.<\/p>\n\n\n\n<pre id=\"9fea\" class=\"wp-block-code graf graf--pre graf-after--p\"><code>git checkout master\ngit merge --squash dao\ngit commit -m \"Added DB and DAO\"\ngit push<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<div class=\"entry-summary\">\nIn the previous step we initialized a spring boot project so that&hellip;\n<\/div>\n<div class=\"link-more\"><a href=\"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-2-2ffb7e2550d5\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &ldquo;Create the Data Repository&rdquo;<\/span>&hellip;<\/a><\/div>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[41],"tags":[53,52,29,51,48,50,42,43,54],"course":[40],"class_list":["post-830","post","type-post","status-publish","format-standard","hentry","category-software-development","tag-dao","tag-database","tag-git","tag-liquibase","tag-lombok","tag-maven","tag-spring","tag-spring-boot","tag-unit-testing","course-spring-with-kubernetes","entry"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":827,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-1-d67f80487848\/","url_meta":{"origin":830,"position":0},"title":"Setup: IDE and New Project","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"\u00a0Its very easy to get a spring boot microservice up and running. You can read any variety of articles on medium (or other service) on how to do that. However, there\u2019s little about how to do some of the more complicated things that you need in order to support a\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":821,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-7-2a141b03db3f\/","url_meta":{"origin":830,"position":1},"title":"Database as a Service","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"Now that we\u2019ve got our service pretty might tightened up lets get started moving towards deploying it. The first step is using a real database instead of the in memory one. Cloud Based Database\u00a0Setup We\u2019re going to use postgreSQL as our database. The most straightforward option is to run postgreSQL\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":828,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-4-dba10da3d834\/","url_meta":{"origin":830,"position":2},"title":"Create a REST Controller","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"In this article we\u2019re going to take the service layer we created in the last step and add a REST interface to it. We\u2019re going to follow the hexagonal design principles we previously discussed and add a functional or component test and explain how those test work and why they\u2019re\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1447,"url":"https:\/\/bullyrooks.com\/index.php\/2023\/05\/14\/unit-tests-vs-component-tests-which-ones-better-for-software-quality\/","url_meta":{"origin":830,"position":3},"title":"Unit Tests vs. Component Tests: Which One&#8217;s Better for Software Quality?","author":"Bullyrook","date":"May 14, 2023","format":false,"excerpt":"Dive into the good and bad of unit tests and component tests in software development. Find out how to get the best of both worlds for top-notch code quality.","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":816,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-12-c6423261a93a\/","url_meta":{"origin":830,"position":4},"title":"Setting up a Kubernetes Cluster","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"Finally, we\u2019re going to be able to deploy our application. We need to get access to a cluster first. Install Tooling We\u2019re going to need more tools in order to get started. Use your OS package management tool to install these tools: Kubectl (Interact with a k8s instance)Minikube (Run a\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":819,"url":"https:\/\/bullyrooks.com\/index.php\/2020\/03\/30\/simple-spring-boot-service-to-kubernetes-application-step-3-f03bdfe30ceb\/","url_meta":{"origin":830,"position":5},"title":"Building a Service Layer","author":"Bullyrook","date":"March 30, 2020","format":false,"excerpt":"In this stage we\u2019re going to build out the service or logical layer of our microservice. I\u2019ll explain adapter and port or hexagonal architecture and covering the usage of mapstruct. Service Design Ports and adapter or hexagonal design is a well discussed concept, so I\u2019m not going to go into\u2026","rel":"","context":"In &quot;Software Development&quot;","block_context":{"text":"Software Development","link":"https:\/\/bullyrooks.com\/index.php\/category\/software-development\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/830","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/comments?post=830"}],"version-history":[{"count":3,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/830\/revisions"}],"predecessor-version":[{"id":878,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/posts\/830\/revisions\/878"}],"wp:attachment":[{"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/media?parent=830"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/categories?post=830"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/tags?post=830"},{"taxonomy":"course","embeddable":true,"href":"https:\/\/bullyrooks.com\/index.php\/wp-json\/wp\/v2\/course?post=830"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}