{"id":266,"date":"2019-08-14T20:47:25","date_gmt":"2019-08-15T03:47:25","guid":{"rendered":"http:\/\/blog.nillsf.com\/?p=266"},"modified":"2019-08-16T12:15:46","modified_gmt":"2019-08-16T19:15:46","slug":"a-quick-look-at-the-ballerina-language","status":"publish","type":"post","link":"https:\/\/nillsf.com\/index.php\/2019\/08\/14\/a-quick-look-at-the-ballerina-language\/","title":{"rendered":"A quick look at the Ballerina language"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Update Aug 16: In the kubernetes part of this blog I mentioned I hit a bug in the kubernetes deployment part. The maintainers of Ballerina provided a fix, I updated the post to reflect that fix.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Yesterday, I was attending the <a href=\"https:\/\/www.meetup.com\/microservices-apis-integration-meetup\/events\/263652405\/\">&#8220;Microservices, APIs and Integration&#8221; Meetup <\/a>in Mountain View. There were two presentations, one great presentation on the need for continuous integrating testing by <a href=\"https:\/\/twitter.com\/davidstanke\">Dave Stank<\/a>. The second talk of the night was delivered by <a href=\"https:\/\/twitter.com\/lakwarus\">Lakmal Warusawithana<\/a>. He touched on the topic of deploying API management right in your service mesh. It was a good talk, showcasing some of the integrations between WSO2 API management and Istio.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What really blew me away during Lakmal&#8217;s talk however was the productivity of the <a href=\"https:\/\/ballerina.io\/\">Ballerina language<\/a>. During his demo, Lakmal built a new service in Ballerina, and during the build phase Dockerfiles were generated, alongside with kubernetes manifests, helm charts and Istio configuration. I was blown away that a programming language could be Docker and Kubernetes aware and build its own &#8216;container&#8217; files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I decided to do some more research into Ballerina and build this demo myself. And I thought, why not do this in the open and share my learnings (and in the meanwhile, do some advocacy for Ballerina).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is Ballerina?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ballerina is a new programming language, primarily developed by the company <a href=\"https:\/\/wso2.com\/\">WSO2<\/a>. Ballerina was specifically designed to work well in distributed systems and is designed to make the network a first class construct. <a href=\"https:\/\/docs.google.com\/presentation\/d\/1yuixfusHrICWn6nxRobDEMjuWaHvn3qMJMzQnjNIkMk\/edit#slide=id.g38f9b4e72b_3_101\">The Ballerina overview deck<\/a>, calls out the following: <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"791\" src=\"\/wp-content\/uploads\/2019\/08\/Ballerina_grey@2x1-1024x791.png\" alt=\"\" class=\"wp-image-274\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/Ballerina_grey@2x1-1024x791.png 1024w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/Ballerina_grey@2x1-300x232.png 300w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/Ballerina_grey@2x1-768x593.png 768w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/Ballerina_grey@2x1.png 1584w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>The Ballerina logo<\/figcaption><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>Ballerina is a compiled, type safe, Turing-complete, concurrent programming language.<\/p><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s dissect all of these:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Compiled<\/strong>: A compiled language that is compiled before runtime into machine code or a binary. <\/li><li><strong>Type safe<\/strong>: A type-safe language is one where the only operations that one can execute on data are the ones that are condoned by the data&#8217;s type (<a href=\"https:\/\/stackoverflow.com\/a\/25157350\">source<\/a>). <\/li><li><strong>Turing-complete: <\/strong>Hard to find a simple explanation here. I if somebody says &#8220;my new thing is Turing Complete&#8221; that means in principle (although often not in practice) it could be used to solve any computation problem. (<a href=\"https:\/\/stackoverflow.com\/questions\/7284\/what-is-turing-complete\">source<\/a>) Most programming languages are Turing complete, but markup languages (HTML, CSS) are not. For a very in-depth review, <a href=\"https:\/\/medium.com\/@evinsellin\/what-exactly-is-turing-completeness-a08cc36b26e2\">check this out<\/a>. <\/li><li><strong>Concurrent: <\/strong>Concurrency means you can have multiple independent executions of a process or task. In Ballerina, concurrency is an inherent part of the concept of a function.  <a href=\"https:\/\/blog.golang.org\/concurrency-is-not-parallelism\">Concurrency is related to but distinct from parallelism<\/a>. <\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Additionally, Ballerina offers both a text-based programming language as well as a graphical sequence-diagram based editor. <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/526\/1*o1syDBdgnHSMoZNMBnGyGw.png\" alt=\"\"\/><figcaption>Example of the Ballerina graphical editor. Taken from the <a href=\"https:\/\/medium.com\/ballerina-techblog\/ballerina-vscode-plugin-graphical-editor-for-ballerina-b6af226178d6\">Ballerina Techblog.<\/a><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">It&#8217;s very hard to describe a language I just realized. If you want to learn more about the language, I would recommend checking out the <a href=\"https:\/\/v1-0-0-alpha.ballerina.io\/learn\/language-specification\/2019R2\/\">Language specification<\/a>. But I wanted to try things out and see this black magic of Ballerina and the auto-generated Docker\/Kubernetes in action.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting up Ballerina and running Hello World<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I&#8217;ll be running this setup on my Ubuntu based WSL. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The latest package to download is available <a href=\"https:\/\/ballerina.io\/downloads\/\">here<\/a>. To download and install do the following commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wget https:\/\/product-dist.ballerina.io\/downloads\/0.991.0\/ballerina-linux-installer-x64-0.991.0.deb\nsudo dpkg -i ballerina-linux-installer-x64-0.991.0.deb<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now that the language is installed, we can start with an <a href=\"https:\/\/ballerina.io\/learn\/quick-tour\/\">hello-world example<\/a>. We&#8217;ll start with creating a new directory, and initializing our program. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir hello-world\ncd hello-world\nballerina init<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This created 2 files: <code>Ballerina.toml<\/code> and <code>hello_service.bal<\/code>. Let&#8217;s have a look at the content of both files, starting with the <code>hello_service.bal<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ A system module containing protocol access constructs\n\/\/ Module objects referenced with 'http:' in code\nimport ballerina\/http;\nimport ballerina\/io;                                                                                                                                                                                                                                                                                        # A service is a network-accessible API                                                                                                               # Advertised on '\/hello', port comes from listener endpoint                                                                                           service hello on new http:Listener(9090) {                                                                                                                                                                                                                                                                      # A resource is an invokable API method                                                                                                               # Accessible at '\/hello\/sayHello                                                                                                                      # 'caller' is the client invoking this resource                                                                                                                                                                                                                                                             # + caller - Server Connector                                                                                                                         # + request - Request                                                                                                                                 resource function sayHello(http:Caller caller, http:Request request) {                                                                                                                                                                                                                                          \/\/ Create object to carry data back to caller                                                                                                         http:Response response = new;                                                                                                                                                                                                                                                                               \/\/ Set a string payload to be sent to the caller                                                                                                      response.setTextPayload(\"Hello Ballerina!\");                                                                                                                                                                                                                                                                \/\/ Send a response back to caller                                                                                                                     \/\/ -> indicates a synchronous network-bound call                                                                                                      error? result = caller -> respond(response);                                                                                                          if (result is error) {                                                                                                                                    io:println(\"Error in responding\", result);                                                                                                        }    }                                                                                                                                        }%                                 <\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is relatively easy to understand, we basically create a service called <code>hello<\/code>, which contains a function <code>sayHello<\/code>, that will return a static message. Let&#8217;s have a look at the <code>Ballerina.toml <\/code>file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>[project]                                                                                                                                             org-name = \"nilfranadmin\"                                                                                                                             version = \"0.0.1\" <\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nothing special here, just some metadata. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s go ahead and build our solution and check it out:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ballerina run hello_service.bal<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This will start our service, which we can access on <code>localhost:9090<\/code>:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"329\" height=\"110\" src=\"\/wp-content\/uploads\/2019\/08\/image-2.png\" alt=\"\" class=\"wp-image-268\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-2.png 329w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-2-300x100.png 300w\" sizes=\"auto, (max-width: 329px) 100vw, 329px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">But indeed, we configured a specific hello service to listen on the sayHello function. So let&#8217;s browse to <code>localhost:9090\/hello\/sayHello<\/code>:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"110\" src=\"\/wp-content\/uploads\/2019\/08\/image-3.png\" alt=\"\" class=\"wp-image-269\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-3.png 400w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-3-300x83.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The quick-tour guide in the Ballerina docs continues from here to use ballerina to interact with Twitter to send a tweet. I might run that example later, but I want to see the Docker\/Kubernetes magic first. Let&#8217;s have a look here.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Docker \/ Kubernetes integration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">So, let&#8217;s take our service, and try to turn it into a container and then into a Kubernetes service running on an existing cluster. If you&#8217;re only interested in the Kubernetes magic, you can skip the next section and continue to the Kubernetes section. If you&#8217;re looking to understand, I recommend following along completely.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We&#8217;ll start with <a href=\"https:\/\/ballerina.io\/learn\/by-example\/docker-deployment.html\">turning our existing hello-world service into a Docker container<\/a>. There&#8217;s 3 changes you&#8217;ll need to make to your existing <code>hello_service.bal<\/code> to make this work. (btw. I assume you already have docker setup and the docker daemon is running)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import ballerina\/http;\nimport ballerina\/io;\n\/\/Change 1: import docker module.\nimport ballerinax\/docker;\n\n\/\/Change 2: add @docker:Expose{} and define http:listener here.\n\/\/Change listener further on to helloWorldEP\n@docker:Expose {}\nlistener http:Listener helloWorldEP = new(9090);\n\n\/\/Change 3: add Docker configuration. Image name and version.\n@docker:Config{\n    name: \"helloworld\",\n    tag: \"v0.1\"\n}\n\nservice hello on helloWorldEP {\n    resource function sayHello(http:Caller caller, http:Request request) {\n\n        http:Response response = new;\n\n        response.setTextPayload(\"Hello Ballerina!\");\n\n        error? result = caller -> respond(response);\n        if (result is error) {\n            io:println(\"Error in responding\", result);\n        }    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And with those three changes made, we can go ahead and build our service and our Docker container:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ballerina build hello_service.bal\nsudo docker run -d -p 9090:9090 helloworld:v0.1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And if we then again connect to our localhost on port 9090, we see our same ballerina service running in a container!<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"402\" height=\"118\" src=\"\/wp-content\/uploads\/2019\/08\/image-4.png\" alt=\"\" class=\"wp-image-270\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-4.png 402w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-4-300x88.png 300w\" sizes=\"auto, (max-width: 402px) 100vw, 402px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s have a look at what happened. During the build phase, Ballerina created a couple of files:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tree\n.                                                                                                                                                     \u251c\u2500\u2500 Ballerina.toml                                                                                                                                    \u251c\u2500\u2500 ballerina-internal.log                                                                                                                            \u251c\u2500\u2500 hello_service.bal\n\u2514\u2500\u2500 target                                                                                                                                                \n    \u251c\u2500\u2500 Ballerina.lock\n    \u251c\u2500\u2500 hello_service                                                                                                                                     \n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 Dockerfile                                                                                                                                    \n    \u2514\u2500\u2500 hello_service.balx\n\n2 directories, 6 files<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">What we see here is that in the target folder, ballerina created our ballerina executable in the <code>hello_service.balx<\/code> file, and created a <code>Dockerfile<\/code> as well in a subfolder. NEAT<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But, our end goal is to run this on a Kubernetes cluster. Which will require us to push our image into a registry. Let&#8217;s push our image into an Azure Container Registry. If you don&#8217;t have one, you can create one in the Azure portal, or use any other registry. What you&#8217;ll need it the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Registry FQDN<\/li><li>Username<\/li><li>Password<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Then we&#8217;ll add that to the <code>@docker:Config<\/code> part of our <code>hello_service.bal<\/code> file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@docker:Config{\n    name: \"helloworld\",\n    tag: \"v0.1\",\n    push:true,\n    registry: \"nilfran.azurecr.io\",\n    username: \"nilfran\",\n    password: \"notSharingMyPWwithYou\"\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With that, we can execute another <code>sudo ballerina build hello_service.bal<\/code>, and if you&#8217;re patient (the upload takes a minute) you&#8217;ll see the image pop up in your registry!<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"587\" height=\"257\" src=\"\/wp-content\/uploads\/2019\/08\/image-5.png\" alt=\"\" class=\"wp-image-271\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-5.png 587w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-5-300x131.png 300w\" sizes=\"auto, (max-width: 587px) 100vw, 587px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">The kubernetes magic<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s now try the same with Kubernetes. First things first, forget about the Docker piece. That was nice, but you don&#8217;t need it at all for the Kubernetes part &#8211; the deployment manager in Ballerina will build and push the image for you. Now, I hit (what I believe to be) <a href=\"https:\/\/github.com\/ballerinax\/kubernetes\/issues\/363\">a bug in the kubernetes deployment manager in Ballerina<\/a> &#8211; <s>but I&#8217;ll walk you through getting to a working example!<\/s> and the maintainers of Ballerina were able to help out with providing a fix &#8211; for which I updated the post.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s start with our code. This will look similar to our Docker code, with a few simple changes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import ballerina\/http;\nimport ballerina\/io;\nimport ballerinax\/kubernetes;\n\n@kubernetes:Service {\n    serviceType: \"LoadBalancer\"\n}\n\nlistener http:Listener helloWorldEP = new(9090);\n\n@kubernetes:Deployment {\n    livenessProbe: true,\n    image: \"nilfran.azurecr.io\/hello-kubernetes:v1.0\",\n    buildImage: true,\n    push: true,\n\/\/    registry: \"nilfran.azurecr.io\", \n    username: \"nilfran\",\n    password: \"nothingToSeeHere\"\n}\n\nservice hello on helloWorldEP {\n    resource function sayHello(http:Caller caller, http:Request request) {\n\n        http:Response response = new;\n\n        response.setTextPayload(\"Hello Ballerina!\");\n\n        error? result = caller -> respond(response);\n        if (result is error) {\n            io:println(\"Error in responding\", result);\n        }    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As you can see, we removed our Docker block, and we changed that with a Kubernetes block. We can go ahead and build this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ballerina build hello_service.bal<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This will build our image, push it to our registry and it will create the necessary yaml files and helm charts. Now, I mentioned that bug before?  That&#8217;s why we removed the registry reference in the kubernetes deployment part of the file.  <s>Here is where you&#8217;ll quickly want to make a change in the yaml file &#8211; to remove a redundant registry name. <\/s> <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><s>vi target\/kubernetes\/hello_service\/hello_service.yaml<\/s><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><s>In that file, you see a line that looks like this:<\/s><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><s>- image: \"nilfran.azurecr.io\/nilfran.azurecr.io\/hello-kubernetes:v1.0\"<\/s> <\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><s>Remove the redundant <\/s><code><s>nilfran.azurecr.io\/<\/s><\/code><s> (or your container repo name).<\/s> <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With that done, you can do a <code>kubectl apply -f target\/kubernetes\/hello_service\/hello_service.yaml<\/code> and see everything get deployed. A <code>kubectl get all<\/code> should show the following resources:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>NAME                                            READY   STATUS      RESTARTS   AGE\npod\/hello-service-deployment-6667b7dbb6-hrnpj   1\/1     Running     0          27m\n\nNAME                        TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)          AGE\nservice\/helloworldep-svc    LoadBalancer   10.0.117.180   52.191.184.15   9090:32159\/TCP   59m\n\n\nNAME                                       READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps\/hello-service-deployment   1\/1     1            1           59m\n\nNAME                                                  DESIRED   CURRENT   READY   AGE\nreplicaset.apps\/hello-service-deployment-6667b7dbb6   1         1         1       27m<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The second entry here is a service, of type LoadBalancer, which is publically accessible. Go over to that IP and access the service and now you have your Ballerina service up and running in Kubernetes.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"532\" height=\"112\" src=\"\/wp-content\/uploads\/2019\/08\/image-6.png\" alt=\"\" class=\"wp-image-272\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-6.png 532w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/image-6-300x63.png 300w\" sizes=\"auto, (max-width: 532px) 100vw, 532px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I hope that I showed what amazed me yesterday during the Meetup. How easy it is to from within Ballerina create kubernetes YAML and automatically create and push your Docker images to a registry. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Update Aug 16: In the kubernetes part of this blog I mentioned I hit a bug in the kubernetes deployment part. The maintainers of Ballerina provided a fix, I updated the post to reflect that fix. Yesterday, I was attending the &#8220;Microservices, APIs and Integration&#8221; Meetup in Mountain View. There were two presentations, one great [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":274,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[5],"tags":[22,18,16],"class_list":["post-266","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-open-source","tag-ballerina","tag-kubernetes","tag-open-source"],"jetpack_featured_media_url":"https:\/\/nillsfblog.blob.core.windows.net\/media\/2019\/08\/Ballerina_grey@2x1.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/266","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/comments?post=266"}],"version-history":[{"count":5,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/266\/revisions"}],"predecessor-version":[{"id":278,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/266\/revisions\/278"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/media\/274"}],"wp:attachment":[{"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/media?parent=266"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/categories?post=266"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/tags?post=266"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}