{"id":150,"date":"2020-08-04T08:00:00","date_gmt":"2020-08-04T06:00:00","guid":{"rendered":"https:\/\/danilov.es\/?p=150"},"modified":"2025-03-13T11:33:37","modified_gmt":"2025-03-13T10:33:37","slug":"applied-bdd-and-performance-testing","status":"publish","type":"post","link":"https:\/\/danilov.es\/index.php\/2020\/08\/04\/applied-bdd-and-performance-testing\/","title":{"rendered":"Applied BDD and Performance Testing"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In the <a href=\"https:\/\/danilov.es\/index.php\/2020\/07\/24\/is-bdd-and-performance-testing-a-good-mix\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>previous article<\/strong><\/a> we were analyzing the benefits of designing a process where mixing BDD with Performance Testing would make total sense. As I like to believe, apart from generating wild ideas, I make them happen. Some long time ago the <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/NightCodeLabs\" target=\"_blank\"><strong>NightCodeLabs<\/strong><\/a> team was formed and we developed a solution to this challenge. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We chose the Java ecosystem because the team was professionally using this programming language back when the project was started, and we were aiming to solve a need we might have had at some point in our day-to-day jobs.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this article you\u2019ll get a general overview on how the solution works and how you can actually reuse the existing BDD functional test code and write performance ones.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Architecture<\/h2>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/dEM9RVeGzXLMqaRMNh-9jLDfpCqa3GG1ihHX3GTS47_DIl-_4Sd5RJO9HHFZOiVfgwPR1fu3zFUcsgQixWPht9oAqEO3bQ0B8tl82q4W8TsgxWhDDwW6v1AXJ-GIXsPrrHDDeS-G\" width=\"624\" height=\"327\"><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">The Test Project<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">A java maven project containing BDD scenarios in Cucumber and a test automation framework of your choice (eg: rest-assured, Selenium, etc). This is where the Performance Tests will live.&nbsp;<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Pretzel<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The test framework we\u2019ll use in order to make our lives easier while attempting to do load and performance testing with BDD. <a href=\"https:\/\/github.com\/NightCodeLabs\/pretzel\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Pretzel<\/strong><\/a> starts and terminates both the worker and master instances between each test, to allow the rest of the communication to happen and to be able to get individual results for each of the scenarios. Apart from that, the rest of the communication is done just with the worker: it sends out the information on what needs to be tested, it checks the status of the execution and once the execution is finished, it reads the results from the generated .csv file. Once this is done, the instances are terminated, and the cycle is repeated if new scenarios are to be executed.&nbsp;&nbsp;<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Master<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">This is where all the magic is happening. The whole solution uses <a rel=\"noreferrer noopener\" href=\"https:\/\/locust.io\/\" target=\"_blank\"><strong>Locust<\/strong><\/a> to generate multiple users, to control how many of them are active per second, etc. Locust originally is a python based load testing tool, which happily allows to build clients in different programming languages so anyone can use it in their own technological ecosystem. There are different clients already out there for languages such as go or java. If you don&#8217;t find one, you could build your own.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Even though the project itself and the code doesn\u2019t need to have anything related to python, in order for the whole solution to work, you\u2019ll still need to have python installed in the machine you\u2019ll be executing, together with a version of locust.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Worker<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">This is the client which interacts with the master instance in order to translate the java code into something which locust can understand. The worker featured in Pretzel is <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/myzhan\/locust4j\" target=\"_blank\"><strong>locust4j<\/strong><\/a>, which is doing a super great job as a client in a simple project setup, but has it\u2019s challenges in integrating in slightly more complex architectures that include BDD with Service\/Page Objects. At <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/NightCodeLabs\" target=\"_blank\"><strong>NightCodeLabs<\/strong><\/a> we were trying to have it integrated by default in the Test Project, but we turned out with a lot of code which is now Pretzel. Finally, locust4j lives as a dependency in Pretzel. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Your first Performance Test with BDD<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\" style=\"font-size:11px\"><strong>Notes<\/strong>: The paragraphs to follow is based on the <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/NightCodeLabs\/pretzel-example\" target=\"_blank\"><strong>example project<\/strong><\/a> we&#8217;ve build at NightCodeLabs. Both the repo and the below guide are  meant to show how this can work, rather to demonstrate a perfect BDD example or testing patterns.  Before starting, make sure you go through the <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/NightCodeLabs\/pretzel-example#installation-guide\" target=\"_blank\"><strong>installation guide<\/strong><\/a>. Grab a beer or a coffee, as installing locust for the first time might take a while. Or avoid all of that and just launch the docker container. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">About the system in test <\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">For this example we have chosen to do some API testing, based on <strong><a rel=\"noreferrer noopener\" href=\"https:\/\/yesno.wtf\/#api\" target=\"_blank\">this simple and public API<\/a><\/strong>. This is their documentation: <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"209\" src=\"https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1024x209.png\" alt=\"\" class=\"wp-image-153\" srcset=\"https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1024x209.png 1024w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-300x61.png 300w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-768x156.png 768w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image.png 1070w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We already have the following functional test case, which we&#8217;d like to reuse into a Performance one:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"markdown\" class=\"language-markdown line-numbers\">Feature: Functional Test\n\n  @Functional\n  Scenario: Request a Forced yes Answer\n    When a forced yes is requested\n    Then the corresponding yes answer is returned\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This feature file sits in a project with the following folder structure:<\/p>\n\n\n\n<pre title=\"File Tree\" class=\"wp-block-code\"><code lang=\"markdown\" class=\"language-markdown\">-- \/src\/main\/java\n     \/serviceobjects\/ForcedAnswer.java\n-- \/test\/java\n     \/runner\/TestRunner.java\n     \/steps\/Definitions.java\n-- \/test\/resources\n     \/Functional.feature\n-- pom.xml\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Behind the Functional Test, we have the following code:<\/p>\n\n\n\n<pre title=\"Definitions.java\" class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">package steps;\nimport cucumber.api.java.en.Then;\nimport cucumber.api.java.en.When;\nimport serviceobjects.ForcedAnswer;\n\npublic class Definitions {\n\n\tForcedAnswer forcedAnswer = new ForcedAnswer();\n\t\n\t@When(\"^a forced (.+) is requested$\")\n\tpublic void aForcedAnswerTypeIsRequested(String answerType) {\n\t\tforcedAnswer.aForcedAnswerTypeIsRequested(answerType);\n\t}\n\n\t@Then(\"^the corresponding (.+) answer is returned$\")\n\tpublic void theCorrespondingAnswerTypeIsReturned(String answerType) {\n        forcedAnswer.theCorrespondingAnswerTypeIsReturned(answerType);\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Service Object class which holds all the methods for forcing an answer inside the API is using the RestAssured testing library. You can use whatever you like here, including UI Testing.<\/p>\n\n\n\n<pre title=\"ForcedAnswer.java\" class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">package serviceobjects;\n\nimport io.restassured.RestAssured;\nimport io.restassured.http.Method;\nimport io.restassured.path.json.JsonPath;\nimport io.restassured.response.Response;\nimport io.restassured.specification.RequestSpecification;\nimport org.junit.Assert;\n\npublic class ForcedAnswer {\n\n    public ForcedAnswer() {}\n    private String requestAnswer;\n\n    public void aForcedAnswerTypeIsRequested(String answerType) {\n        RestAssured.baseURI = \"https:\/\/yesno.wtf\/api\";\n        RequestSpecification httpRequest = RestAssured.given();\n        Response response = httpRequest.request(Method.GET, \"\/?force=\" + answerType);\n        JsonPath answer = response.getBody().jsonPath();\n        System.out.println(answer.prettyPrint());\n        requestAnswer = answer.getString(\"answer\");\n    }\n\n    public void theCorrespondingAnswerTypeIsReturned(String answerType) {\n        Assert.assertEquals(\"Correct answer returned\", answerType , requestAnswer);\n\n    }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Adding the Performance Test<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">First of all, add the pretzel dependency to your maven project:<\/p>\n\n\n\n<pre title=\"pom.xml\" class=\"wp-block-code\"><code lang=\"xml\" class=\"language-xml line-numbers\">\t&lt;dependency&gt;\n    \t   &lt;groupId&gt;com.github.nightcodelabs&lt;\/groupId&gt;\n    \t   &lt;artifactId&gt;pretzel&lt;\/artifactId&gt;\n    \t   &lt;version&gt;0.0.2&lt;\/version&gt;\n\t&lt;\/dependency&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s add the BDD Magic to Performance Testing:<\/p>\n\n\n\n<pre title=\"Performance.feature\" class=\"wp-block-code\"><code lang=\"markdown\" class=\"language-markdown line-numbers\">Feature: Performance Test\n\n  @Performance\n  Scenario: Request a forced yes answer\n    When 100 users request a forced yes at 10 users\/second for 1 min\n    Then the answer is returned within 10000 milliseconds<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Looks cool, right? Let&#8217;s update our existing step definitions. To make it work, we&#8217;ll need to:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>import pretzel, and create a new instance of it<\/li><li>use the doPretzel for the When (to understand better what each parameter is used for, you can check out<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/myzhan\/locust4j\/blob\/master\/src\/main\/java\/com\/github\/myzhan\/locust4j\/Locust.java\" target=\"_blank\"><strong> locust4j documentation<\/strong><\/a>). For simplicity, we recommend using the value of your maximum users as also the weight and the maxRPS<\/li><li>use the checkMaxResponseTImeAboveExpected for the Then. The scenario we&#8217;re designing will fail just in case the responses take more than the expected time. This can be further on enhanced to fail if there are a certain quantity of failures while doing the requests, if the failures\/second are above a certain threshold, or any other crazy combination you could think of. <\/li><\/ul>\n\n\n\n<pre title=\"Definitions.java\" class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">package steps;\n\nimport cucumber.api.java.en.Then;\nimport cucumber.api.java.en.When;\nimport org.junit.Assert;\nimport com.github.nightcodelabs.pretzel.Pretzel;\nimport serviceobjects.ForcedAnswer;\n\n\npublic class Definitions {\n\n\tPretzel pretzel = new Pretzel();\n\tForcedAnswer forcedAnswer = new ForcedAnswer();\n\n\n\t@When(\"^a forced (.+) is requested$\")\n\tpublic void aForcedAnswerTypeIsRequested(String answerType) {\n\t\tforcedAnswer.aForcedAnswerTypeIsRequested(answerType);\n\t}\n\n\t@Then(\"^the corresponding (.+) is returned$\")\n\tpublic void theCorrespondingAnswerTypeIsReturned(String answerType) {\n\t\tforcedAnswer.theCorrespondingAnswerTypeIsReturned(answerType);\n\t}\n\n\t@When(\"^(.+) users request a forced yes at (.+) users\/second for (.+) min$\")\n\tpublic void usersRequestForcedYesAnswerAtRateMinute(Integer maxUsers, Integer usersLoadPerSecond, Integer testTime) throws Throwable {\n\t\tpretzel.doPretzel(maxUsers,usersLoadPerSecond, testTime, maxUsers, maxUsers, \"ForcedYes\");\n\t}\n\n\t@Then(\"^the answer is returned within (.+) milliseconds$\")\n\tpublic void theAnswerIsReturnedWithingMilliseconds(Long expectedTime) {\n\t\tAssert.assertFalse(pretzel.checkMaxResponseTimeAboveExpected(expectedTime));\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You&#8217;ll notice that up until now we haven&#8217;t reused any code, and you&#8217;re wondering most probably where will all of that go. Don&#8217;t worry, actually this will go into into the &#8220;ForcedYes&#8221; class we&#8217;ll need to create (and which pretzel knows how to read):<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>in src\/main\/java create a pretzel\/ForcedYes.java extending the Task from Pretzel<\/li><li>inside the execute block, add the code from the service objects<\/li><li>call performance.recordSuccess and recordFailure (in a try\/catch block). Like this, we are able to record if we start getting other types of responses meanwhile we execute the test on extreme load<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Finally the class would looks something like this: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">package pretzel;\n\nimport com.github.nightcodelabs.pretzel.performance.Task;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport serviceobjects.ForcedAnswer;\n\npublic class ForcedYes extends Task {\n\t\n    private static final Logger logger = LoggerFactory.getLogger(ForcedYes.class);\n    private int weight;\n    ForcedAnswer forcedAnswer = new ForcedAnswer();\n\n    public ForcedYes(Integer weight){\n        this.weight = weight;\n    }\n\n    @Override\n    public int getWeight() {\n        return weight;\n    }\n\n    @Override\n    public String getName() {\n        return \"Forced Yes\";\n    }\n\n    @Override\n    public void execute() {\n        try {\n            forcedAnswer.aForcedAnswerTypeIsRequested(\"yes\");\n            forcedAnswer.theCorrespondingAnswerTypeIsReturned(\"yes\");\n            performance.recordSuccess(\"GET\", getName(), forcedAnswer.getResponseTime(), 1);\n        } catch (AssertionError | Exception error){\n            performance.recordFailure(\"GET\",getName(), forcedAnswer.getResponseTime(),\"Yes has not been returned\");\n            logger.info(\"Something went wrong in the request\");\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s it! Now we&#8217;re all set to actually run it. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Buuuut&#8230; we&#8217;re missing something: the reports. Let&#8217;s say we&#8217;re using a version of extentreports, and we want to integrate the graphs generated by pretzel inside that report. It&#8217;s simple: <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>update the runner, initiating the report directory inside the TestRunner class:<\/li><\/ul>\n\n\n\n<pre title=\"TestRunner.java\" class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">\tprivate static Pretzel pretzel = new Pretzel();\n\n\t@BeforeClass\n\tpublic static void beforeClass() {\n\t     pretzel.initiateReportDirectory();\n\t}\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>in the steps folder, add a Hooks.java class, attaching the graphs of performance scenarios in the extentreports.<\/li><\/ul>\n\n\n\n<pre title=\"Hooks.java\" class=\"wp-block-code\"><code lang=\"java\" class=\"language-java line-numbers\">package steps;\n\nimport java.io.IOException;\nimport com.vimalselvam.cucumber.listener.Reporter;\nimport cucumber.api.Scenario;\nimport cucumber.api.java.After;\nimport com.github.nightcodelabs.pretzel.Pretzel;\n\npublic class Hooks {\n   Pretzel pretzel = new Pretzel();\t\n\n   @After(order = 0)\n   public void AfterSteps(Scenario scenario) throws IOException {\n     if (scenario.getSourceTagNames().contains(\"@Performance\")) { \n       Reporter.addScreenCaptureFromPath(pretzel.getGeneratedChartFilePath(),\"Performance Results\");\n     }\n   }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now we are really ready to run it. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After the execution is finished we can see that the Performance Test Feature is part of the Extent Reports:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"508\" src=\"https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1-1024x508.png\" alt=\"\" class=\"wp-image-164\" srcset=\"https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1-1024x508.png 1024w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1-300x149.png 300w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1-768x381.png 768w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1-1536x762.png 1536w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1-2048x1015.png 2048w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-1-216x108.png 216w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">and that the last step of the Scenario has an image attached, which, if you&#8217;re executing Load and Performance Testing, you&#8217;ll be interested to analyze:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"563\" src=\"https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-2-1024x563.png\" alt=\"\" class=\"wp-image-165\" srcset=\"https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-2-1024x563.png 1024w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-2-300x165.png 300w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-2-768x422.png 768w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-2-1536x844.png 1536w, https:\/\/danilov.es\/wp-content\/uploads\/2020\/08\/image-2-2048x1125.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Further Work<\/h2>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/2hGOlxvxNPNHaTXybvwSN2i232BXf5xJCNClmCRyiRtTXurR-atSxfEwoMDnTpANwDvtS8jkSMQu5dtV62oJsS_jMbXJ4PXTEfzt0uqGk6apGkXs3myZoxIurf4Tz4A0YqpURDg2\" width=\"410\" height=\"230\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Not-so-humbly speaking, I am pretty happy with what pretzel can do, but the current design does come with some improvable points:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>concurrency &#8211; the current implementation allows just sequential executions<\/li><li>it&#8217;s heavy &#8211; it can be executed just in the same machine where the test code is running, and, depending on what scenarios one might have, this can prove quite expensive if you&#8217;re running it super frequent on your CI\/CD<\/li><li>it has that extra code (src\/main\/java\/pretzel) that extends the Task, which could be avoided<\/li><li>as any other test automation tool, it tells you there are problems, but it doesn&#8217;t tell you why<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">All of these points can definitely be improved if there is enough interest in the tool out there. <a href=\"https:\/\/github.com\/NightCodeLabs\/pretzel#how-to-contribute\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Care to contribute with a PR?<\/strong><\/a> We can make this great together! <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous article we were analyzing the benefits of designing a process where mixing BDD with Performance Testing would make total sense. As I&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/danilov.es\/index.php\/2020\/08\/04\/applied-bdd-and-performance-testing\/\">Continue Reading<span class=\"screen-reader-text\">Applied BDD and Performance Testing<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":151,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[4,51,52,57,54,61,53,60,56,48,59,49,55,62,58,3],"class_list":["post-150","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-thoughts","tag-automation","tag-bdd","tag-behaviour","tag-cucumber","tag-development","tag-docker","tag-driven","tag-extentreports","tag-java","tag-load","tag-maven","tag-performance","tag-pretzel","tag-python","tag-restassured","tag-test","entry"],"_links":{"self":[{"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/posts\/150","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/comments?post=150"}],"version-history":[{"count":16,"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/posts\/150\/revisions"}],"predecessor-version":[{"id":241,"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/posts\/150\/revisions\/241"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/media\/151"}],"wp:attachment":[{"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/media?parent=150"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/categories?post=150"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/danilov.es\/index.php\/wp-json\/wp\/v2\/tags?post=150"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}