{"id":14534,"date":"2021-12-02T11:55:55","date_gmt":"2021-12-02T10:55:55","guid":{"rendered":"https:\/\/www.centigrade.de\/?post_type=blog&#038;p=14534"},"modified":"2022-02-07T09:26:18","modified_gmt":"2022-02-07T08:26:18","slug":"how-to-engage-graphql-net-and-react-together-part-i","status":"publish","type":"blog","link":"https:\/\/www.centigrade.de\/en\/blog\/how-to-engage-graphql-net-and-react-together-part-i\/","title":{"rendered":"How to engage GraphQL, .Net and React together. Part I."},"content":{"rendered":"<p>In the world of programming nowadays there are lot of technologies and huge amount of frameworks to build any kind of application for any needs. But these technologies sometimes are divided into layers which intersect quite rarely. For instance, the Web world has numbers of Javascript frameworks that help to build vivid UI with various styles, animations, etc. On the other hand, banking software has to be robust, reliable and able to process huge amount of transactions per second. And another world is social networks that should provide a lot of content in mobile environment under conditions of slow internet and not very powerful devices. What if we try to pick up the strength of each technology and combine them?<\/p>\r\n<p>Hi, I\u00b4m <a href=\"https:\/\/www.centigrade.de\/de\/unternehmen\/team#mikhail.shabanov\">Mikhail<\/a> from Centigrade. This is the first article of the technical blog series about GraphQL Web-API, its implementation in .Net 6.0 and how it should be consumed by React client.<!--more--><\/p>\r\n<h2>Target application<\/h2>\r\n<p>I don\u00b4t want to create a new hello world or bookstore example to show graphql, .net and react in practice. I want to solve real existing user needs we have in our team to have a real use case for the demonstration. With benefits and disadvantages included.<\/p>\r\n<p>Home office lasting through 2020 and 2021 broke our lifestyle and habits. Maybe IT guys were the only ones who did not notice it. But sometimes even we still need to say a couple of words to each other, share some IT news, discuss new tools, frameworks and cool features. For a long time our team has been using a special chat in MS Teams to stock the information about some good-to-know things, articles and other useful information. But such chat is not the right place for \u201cKnowledge base\u201d.<\/p>\r\n<p>Quick internet scanning for ready-made solutions showed that ready-made \u201cknowledge base\u201d applications gave variety of tools with one disadvantage in common \u2013 all these applications were not developed by us. Let\u2019s eliminate this disadvantage and create our own Knowledge base with blackjack and <a href=\"https:\/\/github.com\/ChilliCream\/hotchocolate\">Hotchocolate<\/a>. And call it <strong>VedaVersum<\/strong>! Veda = knowledge | Versum = Universum.<\/p>\r\n<p>Our application will have:<\/p>\r\n<ul>\r\n<li>Authentication mechanism with every user\u00a0 to be logged-in<\/li>\r\n<li>Screen with the cards list. Every card to contain some text and some metadata with creation time, created user, assigned user (optional) and related card (optional)<\/li>\r\n<li>Panel with your avatar and name and \u201cbell\u201d icon which will show if you have any\u00a0 assigned card<\/li>\r\n<li>\u201cWho\u2019s online\u201d panel. You can see other users coming and leaving in real time.<\/li>\r\n<\/ul>\r\n<h2>Why .Net 6.0?<\/h2>\r\n<p>Since we are going to build a distributed application which should support simultaneous work of more than one user, we need a backend service. When we are talking about backend, we mean stability, reliability, performance. There are just a few platforms that can provide such options. DotNet by Microsoft is one of the mature players in the field. And despite its maturity, it is up to date as it has never been before with its lightweight cross platform 6.0 version. Microsoft had done a lot to simplify the \u201centry threshold\u201d into technology. They have made a lot of tutorials, they have simplified the tooling and development environment setup. Microsoft has built the best developers IDEs until now. You can use classic Visual Studio \u00a0and Visual Studio Code or even any IDE you like and Command Line Interface. And just released new .net version 6.0 has official long term support from Microsoft. \u00a0So a lot of developers start to use .Net in their new projects nowadays. But it still remains the good old .Net with its performance, huge code base, vast majority of the third-party libraries. And there is still-the-same-C# with decades of classic programming, OOP implementation, patterns and all the features which \u201cbearded programmers\u201d love. So, I got carried away. For our application we will need a classic web-server. Asp.Net project will fit our needs.<\/p>\r\n<h2>Why GraphQL?<\/h2>\r\n<p><a href=\"https:\/\/graphql.org\/\">GrapQL<\/a> is a Opensource query language for Web API from Facebook. It ensures more flexibility and efficiency for the app developers than traditional REST API. You can build queries and fetch all the data or specific subsets of data you need in one request. GraphQL server will give you exactly the data you requested. This eliminates the over-fetching problem. Subscriptions are among other GraphQL killing features. The App developer are much more flexible by the benefit of a whole query language without the need waiting for API adoptions or changes. \u00a0We will use it in our solution to notify all the users of cards changing, newcomers and also if someone has assigned a card to you. Also with GraphQL we have a lot of other pleasant out-of-the box features. Such as type checking, playground IDE and auto-generated API documentation.<\/p>\r\n<h2>Why React?<\/h2>\r\n<p>Single Page Applications based on JavaScript frameworks have firmly entered our lives leaving old-fashioned UI concepts behind. Again there is a couple of giants in the field which are very popular among the front-end developers. Angular from Google and React from Facebook. These are excellent UI technologies for creating interactive applications for web, mobile and other platforms. Nowadays React popularity is increasing day by day, it has support from Facebook and growing up community. Comparing React and Angular, I found that React is more lightweight, more simple, more declarative because it\u00b4s a UI Library and not a UI Framework like Angular is. And in case of our simple application, React will allow us to create reach powerful UI with less efforts.<\/p>\r\n<h2>Application design<\/h2>\r\n<p>You can see the basic architecture of the application:<\/p>\r\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-14550\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild1.png\" alt=\"Application Design\" width=\"624\" height=\"209\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild1.png 624w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild1-300x100.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/p>\r\n<p>Our application will have backend with GraphQL API, which will store entities in Database. And <a href=\"https:\/\/en.wikipedia.org\/wiki\/Single-page_application\">Single Page Application (SPA)<\/a> client, that will communicate with API. In this article we will focus on Backend. Our backend will have two entities &#8211; <em>User<\/em> and <em>VedaVersumCard<\/em>. GraphQL will have couple of queries to get users and cards lists. And Mutation to create or update the card. And two subscriptions &#8211; <em>UserAction<\/em> (those who came or left), and <em>CardChanged<\/em>. All details you can see below.<\/p>\r\n<h2>Let\u2019s get started<\/h2>\r\n<p>I\u2019ll describe here all the steps you need to create a project from the scratch by yourself. Ready source code for this solution you can find <a href=\"https:\/\/github.com\/Centigrade\/vedaversum\">on GitHub by this link<\/a><\/p>\r\n<p>In this article we will create backend with GraphQL API from scratch. So, let\u2019s do it.<\/p>\r\n<p>First of all, you should have <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/6.0\">.Net 6.0 SDK<\/a> installed. You can use <a href=\"https:\/\/visualstudio.microsoft.com\/downloads\/\">Visual Studio 22<\/a>, or use <a href=\"https:\/\/code.visualstudio.com\/\">VS Code<\/a> (or any other IDE you like) with <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/core\/tools\/dotnet\">Dotnet CLI<\/a><\/p>\r\n<p>We will create the \u201c<em>ASP.NET Core Empty\u201d<\/em> project with \u201cASP.NET Core 6.0\u201d framework and name it <em>VedaVersum<\/em><\/p>\r\n<p>In Visual Studio we can follow a few simple steps \u2013 start \u201cNew Project\u201d, choose \u201cASP.Net Core Web Application\u201d, then \u201cASP.NET Core Empty\u201d, then choose target network and then give a name to the project.<\/p>\r\n<p>If you are using VS Code, open command line and run these commands:<\/p>\r\n<pre>md VedaVersum\r\ncd VedaVersum\r\ndotnet new web\r\ncode .<\/pre>\r\n<p>This creates a simple ASP.NET application with 2 classes &#8211; <em>Program<\/em> With <em>Main<\/em> method, which constructs and runs the web host. And <em>Startup<\/em> which has 2 methodes. One for setup all needed services in <em>Dependency Injection Container<\/em>, and second is for setup HTTP Request pipeline. This is how initial <em>Configure<\/em> method looks like:<\/p>\r\n<p>&nbsp;<\/p>\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\r\npublic void Configure(IApplicationBuilder app, IWebHostEnvironment env)\r\n{\r\n    app.UseRouting();\r\n\r\n    app.UseEndpoints(endpoints =&gt;\r\n    {\r\n        endpoints.MapGet(&quot;\/&quot;, async context =&gt;\r\n        {\r\n            await context.Response.WriteAsync(&quot;Hello World!&quot;);\r\n        });\r\n    });\r\n}\r\n\r\n<\/pre><\/div>\r\n<p>ASP.Net is arranged so that each HTTP request goes through pipeline of handlers called <em>Middleware<\/em>. <em>Configure<\/em> method describes what middleware will be involved into pipeline. For the moment, there are only Routing middleware and simple endpoint handler that intercepts request to the root address and returns plain text \u201cHello World\u201d as the HTTP response. We can run just created application (in VS Code by command dotnet run), and take a look to that \u201cHello World\u201d in the browser.<\/p>\r\n<p>So far so good. The scaffold of our API is ready, it\u2019s time to add something meaningful to it. Let\u2019s start from our data model. Now we will create folder Model in our solution, and add entities <em>User<\/em>, <em>VedaVersumCard<\/em>, enum <em>VedaVersumCardAction<\/em> and <em>CardActionMessage<\/em><\/p>\r\n<p>&nbsp;<\/p>\r\n<h2>Making GraphQL API<\/h2>\r\n<p>As far as we have created our main entities, it\u2019s time to provide our users the abilities to operate them. Our backend should be able to make standard CRUD operations. Such as create new Knowledge Base cards, read existing cards, edit cards, delete cards and notify users if cards were assigned to them. In terms of GraphQL we should define a Schema and the methods that changes data called Mutations, methods that requesting data called Queries and push notifications from server to client called Subscriptions. To implement the Schema with queries, mutation and subscriptions with any known platforms such as .Net, we should implement methods called resolvers. And there are also should be mappers from native dotnet objects into GraphQL <em>object<\/em> and <em>input<\/em> types.<\/p>\r\n<p>There are several third-party libraries for making GraphQL API with .Net. <a href=\"https:\/\/graphql.org\/code\/#c-net\">Here is the list<\/a>.<\/p>\r\n<p>The <a href=\"https:\/\/github.com\/graphql-dotnet\/graphql-dotnet\">graphql-dotnet<\/a> supposes you to describe all the ObjectTypes manually. This means that for each dotnet business entity you should have appropriate ObjectType. Since we have only two entities, it\u2019s not a big problem. But if we have a rich data model this approach makes solution a bit messy and complicated.<\/p>\r\n<p>In <a href=\"https:\/\/github.com\/ChilliCream\/hotchocolate\">Hotchocolate<\/a> object types are created \u201cunder the hood\u201d, and you can use dotnet business entities right in the resolvers and mutations with no additional classes and conversions. And we will take this library for our solution because everybody love chocolate.<\/p>\r\n<div class=\"tenor-gif-embed\" data-postid=\"14768025\" data-share-method=\"host\" data-aspect-ratio=\"1.33333\" data-width=\"60%\"><a href=\"https:\/\/tenor.com\/view\/chocolate-ill-take-130s-kid-gif-14768025\">Chocolate Ill Take GIF<\/a>from <a href=\"https:\/\/tenor.com\/search\/chocolate-gifs\">Chocolate GIFs<\/a><\/div>\r\n<p><script type=\"text\/javascript\" async=\"\" src=\"https:\/\/tenor.com\/embed.js\"><\/script><\/p>\r\n<p>To use it in our project, first of all we have to reference Hotchocolate assembly as Nuget package. You can use Nuget Packages Manager in Visual Studio to add package <em>HotChocolate.AspNetCore<\/em>. In VS Code you should run command<\/p>\r\n<pre>dotnet add package HotChocolate.AspNetCore<\/pre>\r\n<p>Our GraphQL API service will have queries, mutations and subscriptions. To implement them we should create three separate classes &#8211; VedaVersumQuery, VedaVersumSubscription and VedaVersumMutation. At the moment there is no implementation and I will not write the whole code here, later I will provide the link to the final solution, so you can download it and test.<\/p>\r\n<p>So, queries are just simple c# methods. For example:<\/p>\r\n<p>&nbsp;<\/p>\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/\/ &lt;summary&gt;\r\n\/\/\/ Returns all cards in the base\r\n\/\/\/ &lt;\/summary&gt;\r\npublic Task&lt;IEnumerable&lt;VedaVersumCard&gt;&gt; GetAllCards()\r\n{\r\n    \/\/ Return mock object so far\r\n    return Task.FromResult&lt;IEnumerable&lt;VedaVersumCard&gt;&gt;(new&#x5B;] {new VedaVersumCard\r\n    {\r\n        Id = Guid.NewGuid().ToString(),\r\n        Title = &quot;Very First Card.&quot;,\r\n        Created = DateTimeOffset.Now,\r\n        Content =\r\n            &quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.&quot;,\r\n        UserCreated = Guid.NewGuid().ToString()\r\n    }});\r\n}\r\n\r\n<\/pre><\/div>\r\n<p>For subscriptions we will use InMemorySubscription mechanism and ITopicEventSender provided by HotChocolate. To hook our method to that mechanism, we will add two attributes &#8211; Subscribe and Topic. And that\u2019s all. This is how subscription looks like:<\/p>\r\n<p>&nbsp;<\/p>\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/\/ &lt;summary&gt;\r\n\/\/\/ Subscription event fires when new user arrives online\r\n\/\/\/ &lt;\/summary&gt;\r\n\/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n&#x5B;Subscribe]\r\n&#x5B;Topic]\r\npublic User UserArrived(&#x5B;EventMessage] User user)\r\n{\r\n    return user;\r\n}\r\n\r\n<\/pre><\/div>\r\n<p>In our mutation class we will inject ITopicEventSender and use it to fire the subscription event:<\/p>\r\n<p>&nbsp;<\/p>\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/\/ &lt;summary&gt;\r\n\/\/\/ Notification about user enter\r\n\/\/\/ &lt;\/summary&gt;\r\npublic async Task&lt;User&gt; UserEnters(string userId)\r\n{\r\n    \/\/ ToDo: Mock implementation.\r\n    var user = new User\r\n    {\r\n        Id = userId,\r\n        Name = &quot;Anakin Skywalker&quot;,\r\n        UserImage = &quot;https:\/\/static.wikia.nocookie.net\/starwars\/images\/6\/6f\/Anakin_Skywalker_RotS.png&quot;\r\n    };\r\n\r\n    await _iTopicEventSender.SendAsync(\r\n        nameof(VedaVErsumSubscription.UserArrived),\r\n        user);\r\n    return user;\r\n}\r\n\r\n<\/pre><\/div>\r\n<p>And now the most important thing &#8211; setup services and pipeline middleware. Let\u2019s change Startup class like this:<\/p>\r\n<p>&nbsp;<\/p>\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class Startup\r\n{\r\n    \/\/ This method gets called by the runtime. Use this method to add services to the container.\r\n    \/\/ For more information on how to configure your application, visit https:\/\/go.microsoft.com\/fwlink\/?LinkID=398940\r\n    public void ConfigureServices(IServiceCollection services)\r\n    {\r\n        services\r\n            .AddGraphQLServer()\r\n            .AddInMemorySubscriptions()\r\n            .AddQueryType&lt;VedaVersumBaseQuery&gt;()\r\n            .AddMutationType&lt;VedaVersumMutation&gt;()\r\n            .AddSubscriptionType&lt;VedaVersumSubscription&gt;();\r\n    }\r\n\r\n    \/\/ This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\r\n    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\r\n    {\r\n        app\r\n            .UseWebSockets()\r\n            .UseRouting()\r\n            .UseEndpoints(endpoints =&gt;\r\n            {\r\n                endpoints.MapGraphQL();\r\n            });\r\n    }\r\n}\r\n\r\n<\/pre><\/div>\r\n<p>As we can see HotChocolate does all the \u201cdirty work\u201d for us ConfigureServices method sets up all needed services and hooks up our query, mutation and subscription classes. Configure method sets up WebSockets middleware which is necessary for subscriptions, and then maps GraphQL endpoint.<\/p>\r\n<p>The last but not the least. If you have ever used GraphQL before, you already know that each GrpaphQL endpoint provides some metadata which describe the API. And there are couple of powerful tools like <a href=\"https:\/\/github.com\/graphql\/graphiql\">Graphiql<\/a> and <a href=\"https:\/\/github.com\/graphql\/graphql-playground\">Playground<\/a>. These tools provide some kind of GraphQL IDE. You have a whole documentation as a serviceabout all queries, mutations, subscriptions and data types that provide the endpoint out of the box. And this information is also used as intellisense tooltips when you are writing \u00a0GraphQL queries in the integrated playground there. Maybe you noticed in the code samples above, I\u2019m using XML comments with query, mutation and subscription methods. These comments HotChocolate can build as GraphQL method description and add to the endpoint metadata. To make it happen, you should edit your VedaVersum.csproj file like this:<\/p>\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&lt;PropertyGroup&gt;\r\n    ...\r\n    &lt;GenerateDocumentationFile&gt;true&lt;\/GenerateDocumentationFile&gt;\r\n    &lt;NoWarn&gt;$(NoWarn);1591&lt;\/NoWarn&gt;\r\n&lt;\/PropertyGroup&gt;\r\n\r\n<\/pre><\/div>\r\n<p>This will generate documentation file from that XML comments each time you compile your project.<\/p>\r\n<h2>Banana Cake Pop IDE<\/h2>\r\n<p>In previous versions of hotchocolate library, there was built-in Playground IDE, starting from the version 11, developers created their own IDE <a href=\"https:\/\/chillicream.com\/docs\/bananacakepop\">Banana Cake Pop<\/a>. Now if you start our application and go to localhost:5000\/graphql, you should see that Banana Cake Pop IDE. If you click a book button on the left, you will see the whole API description.<\/p>\r\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-14552\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild2.png\" alt=\"Api Description\" width=\"557\" height=\"353\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild2.png 557w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild2-300x190.png 300w\" sizes=\"auto, (max-width: 557px) 100vw, 557px\" \/><\/p>\r\n<p>You can try to query data:<\/p>\r\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14554\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild3.png\" alt=\"query data\" width=\"557\" height=\"318\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild3.png 1120w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild3-300x171.png 300w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild3-768x438.png 768w\" sizes=\"auto, (max-width: 557px) 100vw, 557px\" \/><\/p>\r\n<p>To start the subscription, you should open two windows, in one of them write this query and hit \u201cplay\u201d button:<\/p>\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nsubscription {\r\n  userArrived {\r\n    id\r\n    name\r\n    userImage\r\n  }\r\n}\r\n\r\n<\/pre><\/div>\r\n\r\n\r\n<p>In the second window write this mutation and hit \u201cplay\u201d button:<\/p>\r\n\r\n\r\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nmutation {\r\n  userEnters(userId: &quot;123-abc&quot;) {\r\n    id\r\n  }\r\n}\r\n<\/pre><\/div>\r\n\r\n\r\n<p>In the first window you will see that subscription message has appeared:<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1120\" height=\"496\" class=\"wp-image-14556\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild4.png\" alt=\"subscription\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild4.png 1120w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild4-300x133.png 300w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/Bild4-768x340.png 768w\" sizes=\"auto, (max-width: 1120px) 100vw, 1120px\" \/><\/figure>\r\n<h2>Conclusion<\/h2>\r\n<p>We have take\u00a0 a look how simple it can be to create GraphQL API using .Net 6.0 and Hotchocolate library, and query this API without any Single Page Application or javascript client sided code. In the next article we will add Authorization to our application, will store all the data in the database, will see all the benefits of GraphQL Data Loaders and finish all the Backend logic. The last part will then focus the Frontend with React. Stay tuned\u2026<\/p>\r\n","protected":false},"author":66,"featured_media":0,"template":"","tags":[177,886,379,885,653,8,638],"class_list":["post-14534","blog","type-blog","status-publish","hentry","tag-net","tag-api","tag-c","tag-graphql","tag-react-en","tag-software-developers","tag-ux-engineering-en-2"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/14534","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog"}],"about":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/types\/blog"}],"author":[{"embeddable":true,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/users\/66"}],"version-history":[{"count":17,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/14534\/revisions"}],"predecessor-version":[{"id":14810,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/14534\/revisions\/14810"}],"wp:attachment":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/media?parent=14534"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/tags?post=14534"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}