{"id":1211,"date":"2022-03-15T10:32:38","date_gmt":"2022-03-15T17:32:38","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=1211"},"modified":"2022-04-05T02:29:10","modified_gmt":"2022-04-05T09:29:10","slug":"build-graphql-apps-with-hasura-and-azure-sql-database","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/build-graphql-apps-with-hasura-and-azure-sql-database\/","title":{"rendered":"Build GraphQL apps with Hasura and Azure SQL Database"},"content":{"rendered":"<p><em>[This post has been created in collaboration with <a href=\"https:\/\/hasura.io\/\">Hasura Inc.<\/a>]<\/em><\/p>\n<p><em>[On this subject, please also make sure you watch the related Data Exposed <a href=\"https:\/\/techcommunity.microsoft.com\/t5\/azure-sql-blog\/instant-realtime-graphql-on-azure-sql-with-hasura-data-exposed\/ba-p\/3271917\">episode<\/a>]<\/em><\/p>\n<h2><a name=\"_Toc97125820\"><\/a>Introduction<\/h2>\n<p>Hasura makes data access easy, by instantly composing a GraphQL API that is backed by databases and services so that the developer team (or API consumers) get productive immediately. The nature of GraphQL itself and Hasura\u2019s dynamic approach makes integration and iteration easy.<\/p>\n<p>Hasura\u2019s event engine makes it possible to embrace cloud-native without having to worry about non-functional things scaling, reliability and delivery guarantees. Developers can easily build business logic that publishes and consumes events, that reacts to changes in data or gets scheduled based on time.<\/p>\n<p>The Hasura GraphQL Engine is a blazing-fast GraphQL server that gives you instant, realtime GraphQL APIs over Azure SQL, with webhook triggers on database events, and remote schemas for business logic.<\/p>\n<p>Hasura helps you build GraphQL apps backed by Azure SQL databases or incrementally move to GraphQL for existing applications using Azure SQL.<\/p>\n<h2><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic1.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1213\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic1.jpg\" alt=\"Image Pic1\" width=\"1302\" height=\"711\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic1.jpg 1302w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic1-300x164.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic1-1024x559.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic1-768x419.jpg 768w\" sizes=\"(max-width: 1302px) 100vw, 1302px\" \/><\/a><\/h2>\n<p>Figure 1 Hasura architectural diagram<\/p>\n<p>The Hasura GraphQL Engine is open source. You can check out the complete repo <a href=\"https:\/\/github.com\/hasura\/graphql-engine\">here<\/a>.<\/p>\n<p>A complete application using Hasura and Azure SQL can be found on GitHub <a href=\"https:\/\/github.com\/Azure-Samples\/azure-sql-db-graphql-hasura\">here<\/a>.<\/p>\n<h5><strong>In this guide, we will:<\/strong><\/h5>\n<ul>\n<li>Create and configure a new Hasura application<\/li>\n<li>Walk through how to integrate your Azure SQL database with Hasura<\/li>\n<li>Write a Vue 3 frontend application to consume your brand-new GraphQL API.<\/li>\n<\/ul>\n<p>By the end of this walkthrough, you&#8217;ll understand the fundamentals of Hasura, have a fully functioning real-time GraphQL CRUD API, and maybe even learn a thing or two about Vue.<\/p>\n<h5><a name=\"_Toc97125821\"><\/a>Requirements<\/h5>\n<ul>\n<li>js<\/li>\n<li>npm\/yarn<\/li>\n<li>Docker, or a Hasura Cloud account\n<ul>\n<li>If not using Docker, an Azure SQL database is also required<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2><a name=\"_Toc97125822\"><\/a>Solution Setup:<\/h2>\n<h2><a name=\"_Toc97125823\"><\/a>Hasura<\/h2>\n<p>If using Docker:<\/p>\n<ul>\n<li>Run docker compose up -d to start the following services:\n<ul>\n<li>Hasura, exposed on localhost:8070<\/li>\n<li>Postgres DB to use as Hasura&#8217;s metadata storage engine<\/li>\n<li>Azure SQL database to use for this tutorial<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>If using Hasura Cloud:<\/p>\n<ul>\n<li>Open your Cloud app, or launch a new one for this tutorial<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic2.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1217\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic2.jpg\" alt=\"Image Pic2\" width=\"1532\" height=\"930\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic2.jpg 1532w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic2-300x182.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic2-1024x622.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic2-768x466.jpg 768w\" sizes=\"(max-width: 1532px) 100vw, 1532px\" \/><\/a><\/p>\n<ul>\n<li>If required, from the &#8220;Add Database&#8221; configuration panel use the &#8220;Heroku&#8221; tab to create &amp; attach a free Heroku Postgres DB<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic3.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1218\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic3.jpg\" alt=\"Image Pic3\" width=\"1637\" height=\"967\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic3.jpg 1637w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic3-300x177.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic3-1024x605.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic3-768x454.jpg 768w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic3-1536x907.jpg 1536w\" sizes=\"(max-width: 1637px) 100vw, 1637px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Finally:<\/p>\n<ul>\n<li>Edit the .env file in this repo, and set VITE_HASURA_GRAPHQL_ENDPOINT to the endpoint of your Hasura application<\/li>\n<li>Using the Hasura web console, navigate to &#8220;Data&#8221; -&gt; &#8220;Connect Database&#8221;<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic34jpg.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1219\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic34jpg.jpg\" alt=\"Image Pic34jpg\" width=\"1407\" height=\"783\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic34jpg.jpg 1407w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic34jpg-300x167.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic34jpg-1024x570.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic34jpg-768x427.jpg 768w\" sizes=\"(max-width: 1407px) 100vw, 1407px\" \/><\/a><\/p>\n<ul>\n<li>Select &#8220;MS-SQL&#8221; as the Database type, and either:\n<ul>\n<li>A) Set the connection string type to be Environment variable, and enter HASURA_MSSQL_DATABASE_URL if using Docker<\/li>\n<li>B) Enter the connection string to your existing Azure SQL database<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic5.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1220\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic5.jpg\" alt=\"Image Pic5\" width=\"1398\" height=\"863\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic5.jpg 1398w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic5-300x185.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic5-1024x632.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic5-768x474.jpg 768w\" sizes=\"(max-width: 1398px) 100vw, 1398px\" \/><\/a><\/p>\n<h2><a name=\"_Toc97125824\"><\/a>Frontend<\/h2>\n<ol>\n<li>Clone <a href=\"https:\/\/github.com\/Azure-Samples\/azure-sql-db-graphql-hasura\">this<\/a> repo<\/li>\n<li>Run yarn install or npm install<\/li>\n<li>Run yarn dev or npm run dev to start the Vue 3 + Vite development server<\/li>\n<li>Visit http:\/\/localhost:3000 to check that the application is running<\/li>\n<\/ol>\n<h2><a name=\"_Toc97125825\"><\/a>Data Models<\/h2>\n<p>We need to add our todo data model to our application before we begin.<\/p>\n<p>The easiest way to do this is via the Hasura web console.<\/p>\n<p>There are two ways that you can create the table:<\/p>\n<ol>\n<li>By using the &#8220;Run SQL&#8221; page to execute the DDL statement:<\/li>\n<\/ol>\n<pre class=\"prettyprint\">CREATE TABLE \"todo\" (\r\n\r\n    id int not null identity(1,1) primary key,\r\n\r\n    description nvarchar(200) NOT NULL,\r\n\r\n    is_completed bit NOT NULL DEFAULT 0\r\n\r\n);<\/pre>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic6.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1222\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic6.jpg\" alt=\"Image Pic6\" width=\"1403\" height=\"876\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic6.jpg 1403w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic6-300x187.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic6-1024x639.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic6-768x480.jpg 768w\" sizes=\"(max-width: 1403px) 100vw, 1403px\" \/><\/a><\/p>\n<ol>\n<li>By using the &#8220;Add table&#8221; page to graphically create our model:<\/li>\n<\/ol>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic7.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1223\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic7.jpg\" alt=\"Image Pic7\" width=\"1412\" height=\"912\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic7.jpg 1412w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic7-300x194.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic7-1024x661.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic7-768x496.jpg 768w\" sizes=\"(max-width: 1412px) 100vw, 1412px\" \/><\/a><\/p>\n<p>After this, we can insert a record or few into the table, so that we have some data to test with and confirm our Vue application is working in a moment.<\/p>\n<p>From the &#8220;Run SQL&#8221; table, execute the following:<\/p>\n<pre class=\"prettyprint\">INSERT INTO \"todo\"\r\n\r\n    (description)\r\n\r\nVALUES\r\n\r\n    ('Learn Vue 3'),\r\n\r\n    ('Be awesome');<\/pre>\n<p>&nbsp;<\/p>\n<p>Checking the &#8220;Browse Rows&#8221; tab in our table, we should see the rows in todo now:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic8.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1225\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic8.jpg\" alt=\"Image Pic8\" width=\"1635\" height=\"908\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic8.jpg 1635w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic8-300x167.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic8-1024x569.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic8-768x427.jpg 768w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic8-1536x853.jpg 1536w\" sizes=\"(max-width: 1635px) 100vw, 1635px\" \/><\/a><\/p>\n<p><a name=\"_Toc97125826\"><\/a><\/p>\n<h2>Try out GraphQL Queries<\/h2>\n<p>Once the table is tracked by Hasura, CRUD APIs are instantly created.<\/p>\n<p>If we query from our GraphiQL Explorer page, we should see we now have a functioning GraphQL API to access these todos:<\/p>\n<p>For example, try the following query:<\/p>\n<pre class=\"prettyprint\">```graphql\r\n\r\n    query {\r\n\r\n        todo {\r\n\r\n            id\r\n\r\n            description\r\n\r\n            Is_completed\r\n\r\n         }\r\n\r\n     }\r\n\r\n```<\/pre>\n<p>You can see the response with the same fields that were requested in the query.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic9.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1229\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic9.jpg\" alt=\"Image Pic9\" width=\"1287\" height=\"1097\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic9.jpg 1287w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic9-300x256.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic9-1024x873.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic9-768x655.jpg 768w\" sizes=\"(max-width: 1287px) 100vw, 1287px\" \/><\/a><\/p>\n<p>Similarly, the APIs for inserting, updating and deleting data are also available as GraphQL Mutations.<\/p>\n<p>Let\u2019s try out a mutation to insert a todo:<\/p>\n<pre class=\"prettyprint\">```\r\n\r\n    mutation insert_todo($description: String!) {\r\n\r\n        insert_todo_one(object: {\r\n\r\n            description: $description\r\n        }) {\r\n\r\n                id\r\n\r\n                description\r\n\r\n                is_completed\r\n         }\r\n\r\n    }\r\n\r\n```<\/pre>\n<p>The \u201cdescription\u201d variable needs to be sent in the request for the mutation to succeed.<\/p>\n<p>Finally, let us look at an example for a GraphQL Subscription.<\/p>\n<pre class=\"prettyprint\">```\r\n\r\n    subscription fetchTodos {\r\n\r\n        todos {\r\n\r\n            id\r\n\r\n            description\r\n\r\n        }\r\n\r\n    }\r\n\r\n```<\/pre>\n<p>The above query will listen to changes in the database for the todos table. If a new row is available, it will return a response with all the todos at that point, including the new one.<\/p>\n<p>&nbsp;<\/p>\n<p><a name=\"_Toc97125827\"><\/a><\/p>\n<h2>Building our Vue App<\/h2>\n<p>We will walk through building a basic Vue 3 application that can Create\/Read\/Delete from these todos.<\/p>\n<h2><a name=\"_Toc97125828\"><\/a>Reading Todos<\/h2>\n<p>Starting from a blank canvas, let&#8217;s add the code to be able to read and display our SQL Server todo rows.<\/p>\n<p>Our App.vue looks like this:<\/p>\n<pre class=\"prettyprint\">&lt;template&gt;\r\n\r\n    &lt;img alt=\"Vue logo\" src=\".\/assets\/logo.png\" \/&gt;\r\n\r\n&lt;\/template&gt;\r\n\r\n&lt;script setup&gt;\r\n\r\n&lt;\/script&gt;<\/pre>\n<p>&nbsp;<\/p>\n<p>What we want to do is:<\/p>\n<ul>\n<li>Write a function that can query our GraphQL API for the todos<\/li>\n<li>When the page is created, initiate this request<\/li>\n<li>Store the todos in the component state on result<\/li>\n<li>Display the todos<\/li>\n<\/ul>\n<p>To query our todos, we can use fetch():<\/p>\n<div>\n<div>\n<pre class=\"prettyprint\">export async function getTodos() {\r\n\r\n    const req = await fetch(HASURA_GRAPHQL_ENDPOINT, {\r\n\r\n        method: \"POST\",\r\n\r\n        body: JSON.stringify({\r\n\r\n            query: `\r\n    \r\n                query {\r\n                \r\n                    todo {\r\n                    \r\n                        id\r\n                        \r\n                        description\r\n                        \r\n                        is_completed\r\n                    \r\n                    }\r\n                \r\n                }\r\n                \r\n            `,\r\n\r\n        }),\r\n\r\n    })\r\n\r\n    const res = await req.json()\r\n\r\n    return res ? .data ? .todo\r\n\r\n}<\/pre>\n<\/div>\n<\/div>\n<p>Integrating this into our App.vue, looks something like this:<\/p>\n<pre class=\"prettyprint\">&lt;template&gt;\r\n    &lt;img alt=\"Vue logo\" src=\".\/assets\/logo.png\" \/&gt;\r\n    &lt;h1 v-if=\"state.todos.length == 0\"&gt;\r\n      No todos\r\n    &lt;\/h1&gt;\r\n    &lt;section v-else&gt;\r\n        &lt;div :key=\"todo.id\" v-for=\"todo in state.todos\"&gt;\r\n            &lt;p&gt;ID: {{ todo.id }}&lt;\/p&gt;\r\n            &lt;input v-model=\"todo.description\" \/&gt;\r\n            &lt;input\r\n                type=\"checkbox\"\r\n                v-model=\"todo.is_completed\"\r\n                :checked=\"todo.is_completed\"\r\n            \/&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/section&gt;\r\n&lt;\/template&gt;\r\n\r\n&lt;script setup&gt;\r\nimport { onMounted, reactive } from \"vue\"\r\n\r\nconst state = reactive({\r\n  todos: []\r\n})\r\n\r\nasync function getAndSetTodos() {\r\n    const todos = await getTodos()\r\n    state.todos = todos\r\n}\r\n\r\nonMounted(async () =&gt; {\r\n    getAndSetTodos()\r\n})\r\n&lt;\/script&gt;<\/pre>\n<p>After we save, Vite will hot-reload our app. Assuming all is well, our page should now look like this:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic10.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-1230\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic10.jpg\" alt=\"Image Pic10\" width=\"1107\" height=\"880\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic10.jpg 1107w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic10-300x238.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic10-1024x814.jpg 1024w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2022\/03\/Pic10-768x611.jpg 768w\" sizes=\"(max-width: 1107px) 100vw, 1107px\" \/><\/a><\/p>\n<p>Success! We&#8217;ve already integrated data-access from our Azure SQL Database!<\/p>\n<h2><a name=\"_Toc97125829\"><\/a>Delete Todo<\/h2>\n<p>The next step is to be able to update the todos we are able to read.<\/p>\n<p>We have already wired up 2-way data binding to the fields of the todos being displayed. We just need to write a function that can receive a &#8220;todo&#8221; object and pass it along to Hasura to delete in the database.<\/p>\n<p>We can do that like this:<\/p>\n<pre class=\"prettyprint\">export async function deleteTodoById(id) {\r\n    const req = await fetch(HASURA_GRAPHQL_ENDPOINT, {\r\n        method: \"POST\",\r\n        body: JSON.stringify({\r\n            query: `\r\n              mutation DeleteTodoByPk($id: Int!) {\r\n                delete_todo_by_pk(id: $id) {\r\n                  id\r\n                }\r\n              }\r\n            `,\r\n            variables: {\r\n                id,\r\n            },\r\n        }),\r\n    })\r\n    const res = await req.json()\r\n    return res?.data?.delete_todo_by_pk\r\n}\r\n\r\n&lt;template&gt;\r\n    &lt;img alt=\"Vue logo\" src=\".\/assets\/logo.png\" \/&gt;\r\n    &lt;h1 v-if=\"state.todos.length == 0\"&gt;\r\n      No todos\r\n    &lt;\/h1&gt;\r\n    &lt;section v-else&gt;\r\n        &lt;div :key=\"todo.id\" v-for=\"todo in state.todos\"&gt;\r\n            &lt;p&gt;ID: {{ todo.id }}&lt;\/p&gt;\r\n            &lt;input v-model=\"todo.description\" \/&gt;\r\n            &lt;input\r\n                type=\"checkbox\"\r\n                v-model=\"todo.is_completed\"\r\n                :checked=\"todo.is_completed\"\r\n            \/&gt;\r\n            &lt;button @click=\"deleteTodoById(todo.id)\"&gt;Delete&lt;\/button&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/section&gt;\r\n&lt;\/template&gt;\r\n<\/pre>\n<p>If we press the &#8220;Delete&#8221; button on our of todos, we should see it disappear in the database.<\/p>\n<h2><a name=\"_Toc97125830\"><\/a>Create Todo<\/h2>\n<p>Finally, let&#8217;s write some code to allow us to insert new todo items.<\/p>\n<p>We will need the underlying GraphQL mutation function first:<\/p>\n<pre class=\"prettyprint\">export async function createTodo(description) {\r\n    const req = await fetch(HASURA_GRAPHQL_ENDPOINT, {\r\n        method: \"POST\",\r\n        body: JSON.stringify({\r\n            query: `\r\n              mutation CreatTodo($description: String!) {\r\n                insert_todo_one(object: {\r\n                  description: $description\r\n                }) {\r\n                  id\r\n                  description\r\n                  is_completed\r\n                }\r\n              }\r\n            `,\r\n            variables: {\r\n                description,\r\n            },\r\n        }),\r\n    })\r\n    const res = await req.json()\r\n    return res?.data?.insert_todo_one\r\n}\r\n<\/pre>\n<p class=\"prettyprint\">And now we need to wire up an input box and submit button to trigger the todo insert:<\/p>\n<pre class=\"prettyprint\">&lt;template&gt;\r\n    &lt;img alt=\"Vue logo\" src=\".\/assets\/logo.png\" \/&gt;\r\n\r\n    &lt;p&gt;Create New Todo&lt;\/p&gt;\r\n    &lt;label for=\"todo-description\"&gt;\r\n      Description\r\n    &lt;\/label&gt;\r\n    &lt;input name=\"todo-description\" v-model=\"state.newTodoDescription\" \/&gt;\r\n    &lt;button @click=\"createTodo(state.newTodoDescription).then(getAndSetTodos)\"&gt;\r\n      Create\r\n    &lt;\/button&gt;\r\n\r\n    &lt;hr \/&gt;\r\n\r\n    &lt;h1 v-if=\"state.todos.length == 0\"&gt;\r\n      No todos\r\n    &lt;\/h1&gt;\r\n    &lt;section v-else&gt;\r\n        &lt;div :key=\"todo.id\" v-for=\"todo in state.todos\"&gt;\r\n            &lt;p&gt;ID: {{ todo.id }}&lt;\/p&gt;\r\n            &lt;input v-model=\"todo.description\" \/&gt;\r\n            &lt;input\r\n                type=\"checkbox\"\r\n                v-model=\"todo.is_completed\"\r\n                :checked=\"todo.is_completed\"\r\n            \/&gt;\r\n            &lt;button @click=\"deleteTodoById(todo.id)\"&gt;Delete&lt;\/button&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/section&gt;\r\n&lt;\/template&gt;\r\n\r\n&lt;script setup&gt;\r\nimport { reactive, onMounted } from \"vue\"\r\nimport { getTodos, createTodo, deleteTodoById } from \".\/utils\"\r\n\r\nconst state = reactive({\r\n    newTodoDescription: \"\",\r\n    todos: [],\r\n})\r\n\r\nasync function getAndSetTodos() {\r\n    const todos = await getTodos()\r\n    state.todos = todos\r\n}\r\n\r\nonMounted(async () =&gt; {\r\n    getAndSetTodos()\r\n})\r\n&lt;\/script&gt;\r\n<\/pre>\n<h2><a name=\"_Toc97125831\"><\/a>In summary<\/h2>\n<p>We learnt how to create a GraphQL backend using Hasura connected to Azure SQL. We started off by creating data models in Azure SQL, tracked them on Hasura for generating GraphQL APIs. Once the APIs were available, we were able to integrate them into a Vue.js app. This implementation could be replicated to any frontend framework of choice (like React.js \/ Angular) etc.<\/p>\n<p>In the end, we get high performance, scalable GraphQL backend with Hasura and Azure SQL.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hasura makes data access easy, by instantly composing a GraphQL API that is backed by databases and services so that the developer team (or API consumers) get productive immediately. The nature of GraphQL itself and Hasura\u2019s dynamic approach makes integration and iteration easy.<\/p>\n","protected":false},"author":32624,"featured_media":81,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[465,504],"class_list":["post-1211","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sql","tag-azuresql","tag-graphql"],"acf":[],"blog_post_summary":"<p>Hasura makes data access easy, by instantly composing a GraphQL API that is backed by databases and services so that the developer team (or API consumers) get productive immediately. The nature of GraphQL itself and Hasura\u2019s dynamic approach makes integration and iteration easy.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/1211","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/users\/32624"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/comments?post=1211"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/1211\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/81"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=1211"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=1211"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=1211"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}