{"id":87522,"date":"2020-07-02T18:44:33","date_gmt":"2020-07-02T18:44:33","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=87522"},"modified":"2022-04-24T20:35:09","modified_gmt":"2022-04-24T20:35:09","slug":"building-and-consuming-graphql-api-in-asp-net-core-3-1","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/building-and-consuming-graphql-api-in-asp-net-core-3-1\/","title":{"rendered":"GraphQL API in ASP.NET Core: Schema Definition, Queries, Mutations, and Resolvers (with 3.1-Era GraphQL-dotnet Examples)"},"content":{"rendered":"<p>It was in the year 2012 that Facebook decided to rebuild their apps to improve performance and efficiency. It was a time when Facebook&#8217;s mobile strategy wasn&#8217;t working because of high network usage. Optimization strategies using caching might have improved the performance, but since the app was too complex, it was thought that the data fetching strategy itself should be changed. Here&#8217;s where GraphQL came in, and today it has become extremely popular among the development community worldwide. GraphQL, developed by Facebook in 2012 and open-sourced 2015, is now maintained by the GraphQL Foundation.<\/p>\n<p>GraphQL is a platform-agnostic, language-neutral query language that has been around for quite some time now and can be used to execute queries and fetch data. Similar to REST, GraphQL is a specification that provides an elegant and flexible way to query your data. This article discusses the features and benefits of GraphQL and then illustrates how one can work with GraphQL in ASP.NET Core 3.1.<\/p>\n<h2>Prerequisites<\/h2>\n<p>To work with the code examples illustrated in this article, you should have Visual Studio 2019 installed on your computer. If you don\u2019t have a copy of it yet, you can grab one from <a href=\"https:\/\/visualstudio.microsoft.com\/downloads\/\">here<\/a>. If you don\u2019t have .NET Core installed in your system, you can download a copy from <a href=\"https:\/\/dotnet.microsoft.com\/download\/archives\">here<\/a>.<\/p>\n<h2>Why do you need GraphQL?<\/h2>\n<p>GraphQL is a JSON-like query language for APIs as well as a server-side runtime for executing your queries. Unlike REST where the request and response are defined by the API, in GraphQL, the client has complete control on what data the API should return. You can integrate GraphQL with ASP.NET, ASP.NET Core, Java, etc.<\/p>\n<p>If you are working on an application that leverages RESTful architecture, the endpoints might grow over time and maintaining them might become a nightmare. On the contrary, with GraphQL, you just need one endpoint <code>api\/graphql<\/code>, and that&#8217;s all. This is another significant difference between REST and GraphQL.<\/p>\n<p>In using GraphQL you need fewer roundtrips to the server, i.e., you need fewer back-and-forth calls to the server to get all the data you need. With REST, you will have several endpoints such as <code>api\/students<\/code>, <code>api\/teachers<\/code>, <code>api\/batches<\/code>, etc.<\/p>\n<p>Unlike REST, when using GraphQL, you will never have too little or too much data &#8211; you can define your queries and all data you need.<\/p>\n<p>When using GraphQL, you need not worry about versioning. The fact is that GraphQL doesn&#8217;t need versioning and as long as you don&#8217;t delete fields from the types, the clients or consumers of the API wouldn&#8217;t break.<\/p>\n<p>When using GraphQL, you would typically need fewer requests and less bandwidth. You need just a single call to the API to get the data you need. Moreover, you can specify the fields you need when making a request. Instead of returning all fields for a type, you can retrieve only what you need hence saving on bandwidth and resource usage.<\/p>\n<p>Similar to Swagger that generates documentation for the REST endpoints, GraphQL can also generate documentation for the GraphQL endpoint.<\/p>\n<p>Albeit all the advantages GraphQL has to offer, there are a few downsides as well. You can read about those by clicking the <a href=\"https:\/\/www.basdecort.com\/graphql-for-dotnet\/\">link<\/a>.<\/p>\n<h2>GraphQL vs REST<\/h2>\n<p>Here&#8217;s a quick look at how GraphQL compares with REST:<\/p>\n<ol>\n<li>Unlike REST where you might need to have several endpoints to get you the data you need, GraphQL exposes only a single endpoint.<\/li>\n<li>REST works on Http only while GraphQL doesn\u2019t need Http to work.<\/li>\n<li>Unlike REST where you can use any Http verb, GraphQL recommends using only the Http POST verb<\/li>\n<li>Unlike REST where the request and response are defined by the API, the clients or the consumers of GraphQL can define what data they need. While the size of the resource is determined by the server when working with REST, in GraphQL, the API defines the available resources, and the client requests only what it needs.<\/li>\n<li>Both REST and GraphQL are platform and language agnostic, and both are adept at returning JSON.<\/li>\n<\/ol>\n<h2>Building Blocks of GraphQL<\/h2>\n<p>The main building blocks of GraphQL include schemas and types.<\/p>\n<h3>Schema<\/h3>\n<p>There is one, and only one endpoint in GraphQL. This endpoint exposes a schema that is used to let the API consumer know the functionality available for the clients to consume, i.e., what data they can expect and the actions they can perform. A Schema in GraphQL is represented by a class that extends the Schema class pertaining to the <code>GraphQL.Types<\/code> namespace.<\/p>\n<p>A schema contains a <code>Query<\/code>, <code>Mutation<\/code>, and a <code>Subscription<\/code>.<\/p>\n<ol>\n<li>Query &#8211; Queries enable you to consume data efficiently. The consumer or the client can mention the field or fields it needs in lieu of getting data for all fields from a particular type. Note that the client can only consume the fields that have been exposed by the API.<\/li>\n<li>Mutation &#8211; In GraphQL mutations are used to send data to the server, i.e., you can take advantage of mutations to add, edit, or delete data. The client can only take advantage of the mutations that have been exposed by the schema to modify the data. It should be noted here that if there are no mutations in a GraphQL schema, the client cannot manipulate the data in the API.<\/li>\n<li>Subscription &#8211; Subscriptions allow a server to send data to its clients, hence notifying them when events occur. Subscriptions provide support for event-driven architectures and for real-time notifications they take advantage of WebSockets.<\/li>\n<\/ol>\n<h3>GraphQL Object Types<\/h3>\n<p>The most fundamental components of a GraphQL schema are object types, which in turn are used to represent the type of object you can retrieve from your API. Object Types in GraphQL are represented by the <code>GraphQL.Types.ObjectGraphType<\/code> class and contain Fields and Methods. While the former is a property in the class, the latter is used to modify field values when needed based on a client query.<\/p>\n<h2>Getting Started: Configuring the GraphQL Middleware<\/h2>\n<p>First off, create a new ASP.NET Core 3.1 MVC project in Visual Studio 2019. Next, follow the steps outlined in the next section to install the necessary NuGet packages.<\/p>\n<h3>Install NuGet Packages<\/h3>\n<p>Since support for GraphQL is not in-built in ASP.NET Core, you\u2019ll need to install the necessary NuGet packages via the NuGet Package Manager or the NuGet Package Manager Console.<\/p>\n<p>To install the required packages, run the following commands at the NuGet Package Manager Console Window:<\/p>\n<pre class=\"lang:c# theme:vs2012\">Install-Package GraphQL\r\nInstall-Package GraphiQL<\/pre>\n<p>Run the application now and browse the <code>\/graphql<\/code> endpoint. Here\u2019s how the output will look in the web browser.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-87540\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/07\/word-image-28.png\" width=\"672\" height=\"621\" \/><\/p>\n<h3>Configuring the GraphQL Middleware<\/h3>\n<p>Once you&#8217;ve installed the necessary NuGet packages, you should add GraphiQL to your ASP.NET Core application by specifying the following in the Configure method of the Startup class.<\/p>\n<pre class=\"lang:c# theme:vs2012\">app.UseGraphiQl(\"\/graphql\");<\/pre>\n<p>To use the above extension method, you should add the following using directive as well.<\/p>\n<pre class=\"lang:c# theme:vs2012\">using GraphiQl;<\/pre>\n<p>You should also add the services mentioned below. Don&#8217;t be confused looking at these types &#8211; you&#8217;ll implement each of these types (classes and interfaces) later in this article.<\/p>\n<pre class=\"lang:c# theme:vs2012\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddScoped&lt;IDependencyResolver&gt;(_ =&gt; new \r\n    FuncDependencyResolver(_.GetRequiredService));\r\n    services.AddScoped&lt;IDocumentExecuter, DocumentExecuter&gt;();\r\n    services.AddScoped&lt;IDocumentWriter, DocumentWriter&gt;();\r\n    services.AddScoped&lt;AuthorService&gt;();\r\n    services.AddScoped&lt;AuthorRepository&gt;();\r\n    services.AddScoped&lt;AuthorQuery&gt;();\r\n    services.AddScoped&lt;AuthorType&gt;();\r\n    services.AddScoped&lt;BlogPostType&gt;();\r\n    services.AddScoped&lt;ISchema, GraphQLDemoSchema&gt;();\r\n    services.AddControllers();\r\n}<\/pre>\n<p>To avoid compilation errors, you may want to comment out this code until all these types have been implemented. You\u2019ll also need to be sure to add using statements to get rid of the errors. This program needs <code>GraphQL.Types<\/code>, <code>GraphQL<\/code>, your <code>Types<\/code> folder, and <code>GraphQL.HTTP<\/code>.<\/p>\n<h2>Building the Object Model<\/h2>\n<p>First off, create the model classes or the entities. This example contains two entities named <code>Author<\/code> and <code>BlogPost<\/code>. Create a solution folder called <em>Models<\/em>; this is where the entity classes will go. Inside this folder, create two <em>.cs<\/em> files named <em>Author.cs<\/em> and <em>BlogPost.cs<\/em> with the following content.<\/p>\n<p><strong>Author.cs<\/strong><\/p>\n<pre class=\"lang:c# theme:vs2012\">public class Author\r\n    {\r\n        public int Id { get; set; }\r\n        public string FirstName { get; set; }\r\n        public string LastName { get; set; }\r\n    }<\/pre>\n<p><strong>BlogPost.cs<\/strong><\/p>\n<pre class=\"lang:c# theme:vs2012\">public class BlogPost\r\n    {\r\n        public int Id { get; set; }\r\n        public string Title { get; set; }\r\n        public string Content { get; set; }\r\n        public Author Author { get; set; }\r\n    }<\/pre>\n<p>The <code>BlogPost<\/code> class contains a reference to the <code>Author<\/code> class. Hence a <code>BlogPost<\/code> can be written by only one <code>Author<\/code>, but an <code>Author<\/code> can write many blog posts.<\/p>\n<h2>Building GraphQL Schema<\/h2>\n<p>Since GraphQL is not bound to any language or framework, in particular, it is not adept at understanding the CLR classes, i.e., C# POCO classes. Hence, to query data using GraphQL, you should create a type that extends <code>ObjectGraphType&lt;T&gt;<\/code> and pass the entity type as an argument. You should also register the properties of the class as &#8220;Field&#8221; types so that GraphQL can recognize this type.<\/p>\n<p>Create a folder called <em>Types<\/em> and create the following two classes in the files <em>AuthorType.cs<\/em> and <em>BlogPostType.cs<\/em> files, respectively.<\/p>\n<p><strong>AuthorType.cs<\/strong><\/p>\n<pre class=\"lang:c# theme:vs2012\">public class AuthorType : ObjectGraphType&lt;Author&gt;\r\n    {\r\n        public AuthorType()\r\n        {\r\n            Name = \"Author\";\r\n            Field(_ =&gt; _.Id).Description(\"Author's Id.\");\r\n            Field(_ =&gt; _.FirstName).Description\r\n            (\"First name of the author\");\r\n            Field(_ =&gt; _.LastName).Description\r\n            (\"Last name of the author\");\r\n        }\r\n    }<\/pre>\n<p><strong>BlogPostType.cs<\/strong><\/p>\n<pre class=\"lang:c# theme:vs2012\"> public class BlogPostType : ObjectGraphType&lt;BlogPost&gt;\r\n    {\r\n        public BlogPostType()\r\n        {\r\n            Name = \"BlogPost\";\r\n            Field(_ =&gt; _.Id, type: \r\n            typeof(IdGraphType)).Description\r\n           (\"The Id of the Blog post.\");\r\n            Field(_ =&gt; _.Title).Description\r\n            (\"The title of the blog post.\");\r\n            Field(_ =&gt; _.Content).Description\r\n            (\"The content of the blog post.\");\r\n        }\r\n    }<\/pre>\n<p>You also need a class that would fetch author and blog post related data. To do this, create a file called <em>AuthorQuery.cs<\/em> with the following content inside. Make sure to include using <code>GraphQL.Types<\/code>. You\u2019ll need this using statement in many other classes as well.<\/p>\n<p><strong>AuthorQuery.cs<\/strong><\/p>\n<pre class=\"lang:c# theme:vs2012\">public class AuthorQuery : ObjectGraphType\r\n    {\r\n        public AuthorQuery(AuthorService authorService)\r\n        {\r\n            int id = 0;\r\n            Field&lt;ListGraphType&lt;AuthorType&gt;&gt;(\r\n            name:\"authors\", resolve: context =&gt;\r\n            {\r\n                return authorService.GetAllAuthors();\r\n            });\r\n            Field&lt;AuthorType&gt;(\r\n                name: \"author\",\r\n                arguments: new QueryArguments(new \r\n                QueryArgument&lt;IntGraphType&gt; { Name = \"id\" }),\r\n                resolve: context =&gt;\r\n                {\r\n                    id = context.GetArgument&lt;int&gt;(\"id\");\r\n                    return authorService.GetAuthorById(id);\r\n                }\r\n            );\r\n            Field&lt;ListGraphType&lt;BlogPostType&gt;&gt;(\r\n                name: \"blogs\",\r\n                arguments: new QueryArguments(new \r\n                QueryArgument&lt;IntGraphType&gt; { Name = \"id\" }),\r\n                resolve: context =&gt;\r\n                {\r\n                    return authorService.GetPostsByAuthor(id);\r\n                }\r\n            );\r\n        }\r\n    }<\/pre>\n<p>When working with GraphQL, the client will always make an HTTP POST call which would, in turn, contain the query name, name of the operation and the variables. Now create a <code>POCO<\/code> class which would be used as a model for managing schema, variables and the arguments. You can create this file inside the <em>Controllers<\/em> folder in the project.<\/p>\n<p><strong>GraphQLQueryDTO.cs<\/strong><\/p>\n<pre class=\"lang:c# theme:vs2012\">public class GraphQLQueryDTO\r\n    {\r\n        public string OperationName { get; set; }\r\n        public string NamedQuery { get; set; }\r\n        public string Query { get; set; }\r\n        public string Variables { get; set; }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Next, you should create a GraphQL schema that extends the <code>GraphQL.Types.Schema<\/code> class and the <code>GraphQL.Types.ISchema<\/code> interface, as shown below.<\/p>\n<pre class=\"lang:c# theme:vs2012\">public class GraphQLDemoSchema:Schema, ISchema\r\n    {\r\n        public GraphQLDemoSchema(IDependencyResolver \r\n        resolver):base(resolver)\r\n        {\r\n            Query = resolver.Resolve&lt;AuthorQuery&gt;();\r\n        }\r\n    }<\/pre>\n<p>This is needed to make your query known and available to GraphQL. Note that this class should accept the <code>DependencyResolver<\/code> that is added to the services collection in the <code>ConfigureServices<\/code> method of the Startup class. Here&#8217;s where you can specify <code>Query<\/code>, <code>Mutation<\/code> and <code>Subscription<\/code> \u2013 I\u2019ve discussed each of these earlier in this article. For the sake of simplicity, the example specifies only the <code>Query<\/code> here.<\/p>\n<h2>Create the GraphQL API EndPoint<\/h2>\n<p>Next, you should create the API Endpoint with just one action method. The following is the complete source of the <code>GraphQLController<\/code> class.<\/p>\n<pre class=\"lang:c# theme:vs2012\">[Route(\"graphql\")]\r\n    public class GraphQLController : Controller\r\n    {\r\n        private readonly ISchema _schema;\r\n        private readonly IDocumentExecuter _executer;\r\n        public GraphQLController(ISchema schema, \r\n        IDocumentExecuter executer)\r\n        {\r\n            _schema = schema;\r\n            _executer = executer;\r\n        }\r\n        [HttpPost]\r\n        public async Task&lt;IActionResult&gt; Post([FromBody] \r\n        GraphQLQueryDTO query)\r\n        {\r\n            var result = await _executer.ExecuteAsync(_ =&gt;\r\n            {\r\n                _.Schema = _schema;\r\n                _.Query = query.Query;\r\n                _.Inputs = query.Variables?.ToInputs();\r\n                \r\n            });\r\n            if(result.Errors?.Count &gt; 0)\r\n            {\r\n                return BadRequest();\r\n            }\r\n            return Ok(result.Data);\r\n        }\r\n    }<\/pre>\n<p>The <code>AuthorService<\/code> class encapsulates calls to the <code>AuthorRepository<\/code> class.<\/p>\n<pre class=\"lang:c# theme:vs2012\">public class AuthorService\r\n    {\r\n        private readonly AuthorRepository _authorRepository;\r\n        \r\npublic AuthorService(AuthorRepository \r\n        authorRepository)\r\n        {\r\n            _authorRepository = authorRepository;\r\n        }\r\n        public List&lt;Author&gt; GetAllAuthors()\r\n        {\r\n            return _authorRepository.GetAllAuthors();\r\n        }\r\n        public Author GetAuthorById(int id)\r\n        {\r\n            return _authorRepository.GetAuthorById(id);\r\n        }\r\n        public List&lt;BlogPost&gt; GetPostsByAuthor(int id)\r\n        {\r\n            return _authorRepository.GetPostsByAuthor(id);\r\n        }\r\n    }<\/pre>\n<h2>The AuthorRepository class<\/h2>\n<p>The <code>AuthorRepository<\/code> class handles data \u2013 it contains the necessary methods to fetch data. Note the usage of the list of authors and blog posts. These collections are initialized in the constructor.<\/p>\n<p><strong>AuthorRepository.cs<\/strong><\/p>\n<pre class=\"lang:c# theme:vs2012\">public class AuthorRepository\r\n    {\r\n        private readonly List&lt;Author&gt; authors = \r\n        new List&lt;Author&gt;();\r\n        private readonly List&lt;BlogPost&gt; posts = \r\n        new List&lt;BlogPost&gt;();\r\n        \r\npublic AuthorRepository()\r\n        {\r\n            Author author1 = new Author\r\n            {\r\n                Id = 1,\r\n                FirstName = \"Joydip\",\r\n                LastName = \"Kanjilal\"\r\n            };\r\n            Author author2 = new Author\r\n            {\r\n                Id = 2,\r\n                FirstName = \"Steve\",\r\n                LastName = \"Smith\"\r\n            };\r\n            BlogPost csharp = new BlogPost\r\n            {\r\n                Id = 1,\r\n                Title = \"Mastering C#\",\r\n                Content = \"This is a series of articles \r\n                on C#.\",\r\n                Author = author1\r\n            };\r\n            BlogPost java = new BlogPost\r\n            {\r\n                Id = 2,\r\n                Title = \"Mastering Java\",\r\n                Content = \"This is a series of articles \r\n                on Java\",\r\n                Author = author1\r\n            };\r\n            posts.Add(csharp);\r\n            posts.Add(java);\r\n            authors.Add(author1);\r\n            authors.Add(author2);\r\n        }\r\n        public List&lt;Author&gt; GetAllAuthors()\r\n        {\r\n            return this.authors;\r\n        }\r\n        public Author GetAuthorById(int id)\r\n        {\r\n            return authors.Where(author =&gt; author.Id == \r\n            id).FirstOrDefault&lt;Author&gt;();\r\n        }\r\n        public List&lt;BlogPost&gt; GetPostsByAuthor(int id)\r\n        {\r\n            return posts.Where(post =&gt; post.Author.Id == \r\n            id).ToList&lt;BlogPost&gt;();\r\n        }\r\n    }<\/pre>\n<p>Here\u2019s an example of a GraphQL query.<\/p>\n<pre class=\"lang:c# theme:vs2012\">query {\r\n  author (id: 1){\r\n    id\r\n    firstName\r\n    lastName\r\n  }\r\n   blogs\r\n    {\r\n      id\r\n      title\r\n      content\r\n    }\r\n}<\/pre>\n<h2>GraphQL in Action!<\/h2>\n<p>Here\u2019s an example of a GraphQL query you can use to get the data about all authors.<\/p>\n<pre class=\"lang:c# theme:vs2012\">query {\r\n  authors{\r\n    id\r\n    firstName\r\n    lastName\r\n  }\r\n}<\/pre>\n<p>When you execute this query, here\u2019s how the output would look in the GraphiQL tool.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"206\" class=\"wp-image-87541\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/07\/word-image-29.png\" \/><\/p>\n<p>If you would like to get the data about a particular author together with the blogs they have written, you can take advantage of the following query instead.<\/p>\n<pre class=\"lang:c# theme:vs2012\">query {\r\n  author (id: 1){\r\n    id\r\n    firstName\r\n    lastName\r\n  }\r\n  blogs\r\n    {\r\n      id\r\n      title\r\n      content\r\n    }\r\n}<\/pre>\n<p>Now run the application, browse to the <code>graphql<\/code> endpoint and run the query. Figure 2 below shows the output in the GraphiQL tool.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"853\" height=\"281\" class=\"wp-image-87542\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/07\/word-image-30.png\" \/><\/p>\n<h2>Summary<\/h2>\n<p>GraphQL, a new API standard open-sourced by Facebook, is a flexible and powerful alternative to REST. GraphQL provides excellent support for declarative data fetching where the consumer can specify the exact data it needs from an API, i.e., you\u2019re the owner of the data you want to get from the API.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Building a GraphQL API in ASP.NET Core using the GraphQL-dotnet library &#8211; defining schemas, types, queries, mutations, and resolvers; exposing the GraphQL endpoint; and consuming the API from a client. ASP.NET Core 3.1 examples with notes on modern HotChocolate alternatives for current .NET versions.&hellip;<\/p>\n","protected":false},"author":221905,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[48387],"coauthors":[50381],"class_list":["post-87522","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-data-masking"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/87522","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221905"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=87522"}],"version-history":[{"count":9,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/87522\/revisions"}],"predecessor-version":[{"id":87535,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/87522\/revisions\/87535"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=87522"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=87522"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=87522"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=87522"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}