docs: add cloud use case based onboarding guides

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8578
Co-authored-by: Abhijeet Khangarot <26903230+abhi40308@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Aaysha <109507451+aayshasura@users.noreply.github.com>
Co-authored-by: nevermore <31686586+OjasWadhwani@users.noreply.github.com>
Co-authored-by: Priya Sharma <25654753+PriyaSharma45@users.noreply.github.com>
Co-authored-by: Vaishnavi <85152989+vaishnavigvs@users.noreply.github.com>
Co-authored-by: Rob Dominguez <24390149+robertjdominguez@users.noreply.github.com>
GitOrigin-RevId: a2f5154c1dece4513c8b86849a5e54cbf3560cbb
This commit is contained in:
Rikin Kachhia 2023-04-06 20:13:50 +05:30 committed by hasura-bot
parent ec0fec5166
commit ed9f120241
31 changed files with 1351 additions and 0 deletions

View File

@ -0,0 +1,4 @@
{
"label": "Hasura Use Cases",
"position": 3
}

View File

@ -0,0 +1,183 @@
---
description: Building an API Gateway for existing APIs using Hasura
title: Building a Gateway Microservice with Hasura
keywords:
- hasura
- use-case
- gateway
sidebar_label: Building a Gateway microservice with Hasura
sidebar_position: 4
toc_max_heading_level: 5
---
import Thumbnail from '@site/src/components/Thumbnail';
# Building an API Gateway for existing APIs with Hasura
## Introduction
Hasura can serve as a gateway to your existing APIs. It creates a bridge between clients and servers, enabling secure
and efficient data communication. Hasura's Data Federation enables one to compose data from different sources that
reside in independent data stores but are semantically related. Add existing data APIs (REST APIs, GRAPHQL APIs) with
Remote Schemas or Actions in Hasura as a single GraphQL schema without writing any custom code and add it to a Hasura
project to create a gateway which is secure and scalable that deliver high-performance data access.
## Sample use case
This tutorial assumes you have a separate server running with a set of APIs that need to be added behind the gateway.
Let's assume we have two services that needed to be added behind a gateway. The first service is a Hasura project
connected with postgres which contains the order details and can get all the orders for a user and can add a new order.
The second service is a microservice and exposes a REST API, which contains payment-related details.
<Thumbnail src="/img/getting-started/Erd-remote-schemas.png" alt="Gateway Architecture" width="1000px" />
When signing in with Hasura for the first time and clicking for use-case as `Using Hasura as Gateway for existing API`
it creates a Hasura project which we will use to create the gateway.
## Step 1: Connect Hasura project
Create a new project on [Hasura Cloud](https://cloud.hasura.io) for all your services and launch the Console to add the
existing microservice to Hasura.
## Step 2: Connect custom services to Hasura
### Step 2.1: Using Remote Schema
Hasura has the ability to merge your remote GraphQL schemas and provide you with a single, unified GraphQL API using
Remote Schemas. This enables you to write queries and mutations to disparate sources, all from your single Hasura
endpoint.
If the custom server has graphql endpoints, add the server to Hasura as a
[Remote Schema](/remote-schemas/adding-schema.mdx).
1. Head to the `Remote Schemas` tab of the Console and click `Add` on the left sidebar.
2. GraphQL server URL: the endpoint at which your remote GraphQL server is available. This value can be entered manually
or by specifying an environment variable that contains this information.
3. Toggle forwarding all headers sent by the client (when making a GraphQL query) to your remote GraphQL server.
4. Add the required details and click on the `Add Remote Schema` button to merge the Remote Schema.
<Thumbnail src="/img/remote-schemas/add-remote-schemas-interface.png" alt="Merge Remote Schema" width="1100px" />
### Step 2.2: Using Actions
Actions are a convenient and secure way to connect to REST APIs to achieve any business logic you may need, directly
from your GraphQL API.
If the custom server exposes endpoints as a REST API, add the server to Hasura as an
[Action](/actions/rest-connectors.mdx). REST Connectors for Actions are used to integrate existing REST APIs to the
GraphQL API without needing any middleware or modifications to the upstream code.
1. Head to the `Actions` tab of the Console and click `Create` on the left sidebar and then click `New Action`.
2. Define your mutation or query and associated types for your REST API.
<Thumbnail src="/img/getting-started/action-definition.png" alt="Action Definition" width="1000px" />
3. Scroll down to `Configure the REST connectors`
<Thumbnail src="/img/actions/configure-rest-connectors.png" alt="Configure REST connectors for Actions" width="800px" />
The context variables available in transforms are:
| Context variable | Value |
| ------------------ | --------------------------------------- |
| $body | Original body of action request |
| $base_url | Original configured webhook handler URL |
| $session_variables | Session variables |
The Console allows you to preview your transforms while configuring them. To avoid exposing sensitive information on the
console UI the actual environment variables configured on the server are not resolved while displaying the previews
**For example:** If your webhook handler is set as an env var as shown below then pass a mock value for that env var in
the sample context:
<Thumbnail src="/img/actions/transform-sample-context-0.png" alt="Console action webhook handler" width="650px" />
4. Add Request Method: You can change the request method to adapt to your API's expected format.
<Thumbnail src="/img/actions/transform-method.png" alt="Change request method" width="800px" />
5. Request URL: The Request URL template allows you to configure the exact API endpoint to call.
<Thumbnail src="/img/actions/transform-key-value-url.png" alt="Change request URL" width="800px" />
6. Request Body: You can generate a custom request body by configuring a template to transform the default payload to a
custom payload.
<Thumbnail src="/img/actions/transform-body-application-json.png" alt="payload body application/json" width="1100px" />
7. Response Body: You can transform the default body of your HTTP API response by configuring a response transform
template.
<Thumbnail src="/img/actions/transform-response_actions_2.13.png" alt="response transform method" width="800px" />
9. Click on `Create Action` and you can navigate to API tab and check out the Action on the Console.
## Step 3: Add the custom service Hasura project to Gateway
Navigate to the Hasura Console for gateway project. If you do not have a Hasura project created, create a new project
using [Hasura Cloud](https://cloud.hasura.io). Add all the Hasura project's GraphQL endpoints as separate remote schema
by providing GraphQL Service URL as Hasura's GraphQL endpoint.
<Thumbnail src="/img/getting-started/remote-schema-for-gateway.png" alt="Remote Schema for Gateway" width="1000px" />
## Step 4: Explore GraphQL API
Navigate to API tab. On the explorer we can see all the endpoints available in the gateway from all the services.
<Thumbnail src="/img/getting-started/remote-schema-query.png" alt="Remote Schema for Query" width="1000px" />
## Step 5: Add remote schema permissions
### Step 5.1: Enable remote schema permissions
Navigate to [Hasura cloud](https://cloud.hasura.io) and open the project associated with the gateway. Navigate to env
vars and add `HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS` as `true`. This env var
`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS` allows you to set permissions for Remote Schemas.
<Thumbnail src="/img/getting-started/env-var-remote-schema.png" alt="Remote Schema for Query" width="1000px" />
### Step 5.2: Add remote schema permissions
Remote Schema have role-based permissions, allowing you to expose only a certain part of the Remote Schema for the
selected role. You can choose to remove any fields from objects, interfaces and input object types. Doing this will
ensure that these fields are not exposed for the role and they will not be able to query the fields that have been
hidden. Follow along with this [document](/remote-schemas/auth/remote-schema-permissions.mdx) to add permissions for
Remote Schemas.
## Advanced topics
### Logging
Integrate [logging](/observability/overview.mdx) for gateway using Datadog, New Relic, Azure Monitor, Prometheus, or
OpenTelemetry. Navigate to Hasura cloud and, open the gateway project and, navigate the Integration tab to add the
logging service. These are available on Hasura's Professional tier.
### Enable rate limiting
Restricts number of GraphQL operations per minute. This uses a sliding window approach. This means whenever Hasura Pro
receives a request, it will count the rate of that client starting from the current time to last one minute. By default,
the rate-limit happens on the role_name i.e the value provided in `X-HASURA-ROLE`.
1. Navigate to the monitoring section on Hasura Console.
2. Click on `API Limits` and click on `security`.
3. Click on `Rate Limit` and set the values on `Request Rate Limit`.
<Thumbnail src="/img/security/pro-tab-apilimits.png" alt="Hasura Cloud Console api limit tab" />
### Adding relationship for remote schema.
Remote Schema to Remote Schema relationships (a.k.a GraphQL joins) extend the concept of joining data across tables, to
joining across remote GraphQL sources. Once you create relationships between types from the GraphQL schemas, you can
then "join" them by running GraphQL queries.
1. Head to the Remote Schema -> [remote-schema-name] -> Relationships tab.
2. Click the Add a new relationship button.
3. Define the relationship and hit Add Relationship.
<Thumbnail src="/img/schema/configure-relationship-rs-to-rs.png" alt="Defining the relationship" width="800px" />
## Conclusion
Hasura offers a powerful solution for creating a gateway for existing APIs. By leveraging Hasura's features, developers
can improve their API security, performance, and scalability, as well as streamline their development workflow.

View File

@ -0,0 +1,398 @@
---
description: Building a Data API on existing data using Hasura
title: Building a Data API with Hasura
sidebar_position: 1
keywords:
- hasura
- use-case
- data-api
sidebar_label: Building a Data API with Hasura
toc_max_heading_level: 5
---
import Thumbnail from '@site/src/components/Thumbnail';
import Player from '@site/src/components/Player';
import HeadingIcon from '@site/src/components/HeadingIcon';
# Building a Data API on existing data sources with Hasura
## Introduction
Hasura connects to your databases, REST endpoints and GraphQL endpoints to instantly provide a scalable, highly
available, globally distributed, fully managed, secure GraphQL API as a service!
Let's break the above statement down.
As data is no longer in a single data-source, without Hasura you have to build an API that is able to connect to
multiple data-sources, absorb some domain-specific logic, and provide the required security and performance/concurrency.
This process is time consuming and hard to get right.
Instead of spending months writing code to map thousands of tables, embed authorization rules and building APIs, Hasura
allows developers to declaratively configure a web-server in minutes and expose a production-ready API. From building
something by hand to getting that “as a service”.
Take a look at this diagram to understand where Hasura fits in your product.
<Thumbnail
src="/img/getting-started/hasura-use-case/data-api-intro-gif.gif"
alt="Where Hasura fits in your product"
width="1000px"
/>
Hasura also supports many advanced features like authentication, caching, security, monitoring, streaming subscriptions,
running async code on database events, federating data from multiple data sources, REST endpoints and other GraphQL
schemas to build a unified api, and much more.
<br />
## Step 1: Connect a Database
Let's get started by adding your first database to Hasura!
:::info Note
We will be using the Hasura Console in the next few steps, which is a web app to set up Hasura by just making some
clicks! If you landed on this doc and do not have the Hasura console open, we recommend you to go through one of the
quickstart guides [here](/getting-started/overview.mdx) first.
Also assuming that you are connecting to an already running Postgres database instance. The steps are going to be the
same for other databases for the most part. But if required, you can reference [this](/databases/overview.mdx) section
if you are stuck.
:::
1. In your Hasura Console, navigate to the `Data` tab in the top navbar.
2. Click on `Connect Database` button and enter your Postgres database connection string. You can enter the connection
string directly in the `Database URL` input section. (If you are using a different data source, you can select it via
`Data Source Driver` dropdown).
3. Once done, click on `Connect Database`.
This should add the database and there should be a notification. You can select `View Database` in the notification to
view you database.
<Player
src="/img/getting-started/hasura-use-case/data-api-connect-db.webm"
showControls
autoPlay={false}
loop={false}
/>
## Step 2: Track tables/relationships
After adding the database, you will see a list of all the tables that you have under the database schemas. Tables can be
present in the underlying Postgres database without being exposed over the GraphQL API. In order to expose a table over
the GraphQL API, it needs to be tracked.
You can track your tables by hitting the `Track All` button, or track some of them selectively.
<Player
src="/img/getting-started/hasura-use-case/data-api-track-tables.webm"
showControls
autoPlay={false}
loop={false}
/>
As soon as a table is tracked, the corresponding GraphQL schema types and query/mutation/subscription fields will be
automatically generated. These auto-generated fields will allow you to query and mutate data in the table.
Before querying, let's add some relationships. You might have some foreign key relationships in your database tables. We
need to tell hasura to use those relationships, or any other custom relationships and include in the GraphQL API. Using
these relationships, you can then make nested queries. All this will be super clear when we start making queries. But
let's first add some relationships.
1. Once you track a table, go to the table using the left sidebar.
2. Go to `Relationships` tab.
3. Hasura should be auto suggesting some relationships if you have foreign keys set on the table. Add one of the
suggested relationship.
In the example below, I have a schema for a slack like group chat app with users, channels, and workspaces. I'll now add
a relationship `channel_member` in users table.
<Player
src="/img/getting-started/hasura-use-case/data-api-set-relationship.webm"
showControls
autoPlay={false}
loop={false}
/>
## Step 3: Explore GraphQL API
That was it! We got an instant Graphql API on your data already. The Hasura GraphQL Engine automatically generates
GraphQL query/mutation/subscription fields for inserting, updating, deleting or streaming data based on your database's
schema. For any tracked table, a set of queries/mutations/subscriptions are generated and exposed as part of the GraphQL
API.
### Step 3.1: Query the data
With the Hasura GraphQL Engine, you get powerful, full-coverage queries right out of the box. As soon as you connect
your database, you'll be able to query all your related and deeply nested data easily with the power of GraphQL. You'll
also be able to aggregate, filter, sort, and paginate results. Let's make our first query!
1. On the Hasura Console, navigate to `API` tab in the top navbar. API tab is a playground or say a client, where you
can test your query/mutation/subscription responses.
2. You should be able to see your schema tables in the left navbar.
3. Build a GraphQL Query. GraphQL queries are nested queries in which we ask exactly what data we need.
An example query would look something like this. Here I'm querying the users and the `channel_members` info that the
user is related to. Querying channel members is possible due to the relationship we added in the above step:
```graphql
query GetUsers {
users {
name
phone_number
channel_members {
id
}
}
}
```
<Player
src="/img/getting-started/hasura-use-case/data-api-make-query.webm"
showControls
autoPlay={false}
loop={false}
/>
### Step 3.2: Make a mutation
The Hasura GraphQL Engine automatically generates GraphQL mutation fields for inserting, updating, or deleting data
based on your database's schema. For any tracked table, a set of mutations are generated and exposed as part of the
GraphQL API. Let's make our first mutation!
1. On the API tab, select `mutation` from the `Add New` dropdown at the bottom, and click on the plus icon.
2. You should be able to see some autogenerated mutations on your schema. Build a mutation using the explorer on left
navbar, and hit the play button.
For example, I'm inserting a user in my user table in the gif below. The mutation looks like this:
```graphql
mutation AddUser {
insert_users(objects: { email: "jhondoe@gmail.com", name: "John Doe", password: "secretPassword" }) {
affected_rows
}
}
```
<Player
src="/img/getting-started/hasura-use-case/data-api-make-mutation.webm"
showControls
autoPlay={false}
loop={false}
/>
### Step 3.3: Make a subscription
Subscriptions enable you to push data from your database to your clients in real-time, making them a powerful tool for
building reactive applications without the need for continuous server polling. Let's make a subscription now!
For making a subscription, I'll continue using the same example. I have an `online_users` view which checks tells if a
user is online by checking the last seen of the user. We will subscribe to this view, and when we add a new user, we
should see the subscription push the data of the new user in real time!
1. Let's add a subscription by selecting the `Subscription` option from the `Add New` dropdown. My subscription looks
like this:
```graphql
subscription MySubscription {
online_users {
id
last_seen
}
}
```
2. Next I'll open my same hasura project in a new tab, and use the `API` explorer to add a mutation to insert a new
user. Then, in the previous tab, I should be able to see the data of the inserted user in real time.
```graphql
mutation MyMutation {
insert_users(
objects: { email: "jhondoe@gmail.com", last_seen: "now()", name: "John Doe", password: "secretPassword" }
) {
affected_rows
returning {
id
}
}
}
```
<Player
src="/img/getting-started/hasura-use-case/data-api-subscription.webm"
showControls
autoPlay={false}
loop={false}
/>
## Step 4: Add Authorization
:::info Note
As auth is a complex topic, we assume you have some prior knowledge of how it works. Otherwise just ride along and use
the link at the bottom to read more about auth with Hasura.
:::
Authentication verifies the identity of a user or service, and authorization determines their access rights to the
service. The basic premise here is this:
- There might be some publicly available information in your app (for example public channels in a group chat app that
anyone can access without signing in). This information won't need any auth.
- There might be some user specific information in your app, that only the user should be able to see (for example a
user's address information). This information will only be accessible to user if the users sends some info with the
request telling Hasura about their identity.
For working with the user specific information, users need to be authenticated. Actual authentication is handled outside
Hasura. So you need to either have a custom auth service, or use one of the auth providers (like Auth0). Once a user is
authenticated with your auth service, you can either provide a JWT to the Hasura GraphQL Engine containing session
variables like user role, or specify a webhook in order to fetch the session variables on each request.
For authorization, Hasura helps you define granular, role and session variable based permission rules to control access
to your data. These permissions utilize the session variables returned by your authentication service and are granular
enough to control access to every row or column in your database.
Let's take a look at a high-level overview of how this works when Hasura GraphQL Engine receives a request:
<Thumbnail
src="/img/auth/auth-high-level-overview-diagram.png"
alt="Authentication and authorization in
Hasura flow diagram"
/>
Hasura uses the role, session variables and the actual GraphQL query itself to validate against the authorization
permission rules defined by you. If the operation is allowed, it generates an optimized SQL query, which includes the
constraints from the permission rules, and sends it to the database to perform the required operation; fetching the
required rows for queries or inserting, editing or deleting rows for mutations.
#### Authentication
Hasura gives you the power to authenticate users how you want, integrating with many popular auth services or your own
existing custom solution hosted elsewhere.
There are 2 ways to authenticate a user:
1. JWT
2. Webhook
In JWT based authentication, a client requests your auth service to get a JWT. Then you can directly pass the JWT to
Hasura, this JWT should have some custom claims (like user role) which will be used to decide what information to show
to the user.
In Webhook based authentication, a client directly calls hasura with some headers. Hasura calls the webhook service with
each request. The webhook service will use your request headers to determine the auth status of the user and return the
user role and any other information as session variables in the response body.
#### Authorization
Hasura also provides role based authorization, using which you can manage access to your data and APIs by defining roles
and permissions. Hasura's fine-grained access control system allows you to specify which users can access which data
ensuring that your application is secure and robust.
Once you authenticate a user, you will get some session variables which will contain user information like user role,
etc. This information can be used to set up role based access control.
Let's go through a simple example. In my group chat app, I have a `users` table. I want to set access control on this
table such that a user can only access their own information.
Let's go through the steps to do it:
1. Go to `users` table, and open `Permissions` tab.
2. You should see the role `admin` has full access to the table by default.
3. Add a new role `user` in the `Enter new role` input.
4. Let's define some permissions on `user` role. Click on `select` column, and it will open a card. Here we are setting
some permission on selection/querying of the data.
5. In the `Row select permissions`, select `With custom check` and add the permission
`{"id":{"_eq":"X-Hasura-User-Id"}}`. This will tell Hasura to only send the rows which match the above rule. Here the
rule states that the `id` column should be equal to the value of session variable `X-Hasura-User-Id`.
6. Open the `Column select permissions` dropdown, and click `Toggle All` button. This defines which columns the given
role can access.
And we are done. Let's go to the API tab to see this in action.
1. Navigate to `API` tab from top navbar.
2. Query `users` table and don't provide any role based information. We should see all the data as we are providing the
admin secret so we are making this query in the admin role.
3. Now I'll add the `X-Hasura-Role` and `X-Hasura-User-Id` in the headers. This will tell Hasura about the user and role
information. Hitting play button again will only give me the selected user's information.
<Player src="/img/getting-started/hasura-use-case/set-permissions.webm" showControls autoPlay={false} loop={false} />
As you probably have guessed, in a production environment these header values will come from session variables (either
using JWT or webhook). So the actual flow will be something like, the front-end client calls a auth service to generate
a JWT with claims containing `X-Hasura-Role` and other info. This JWT will be sent to Hasura by the client. Hasura
decodes the JWT and gets these header values, and the rest of the flow remains the same.
This was just a tip of the iceberg to the many functionalities Hasura provides for doing Auth. You can read more about
it [here](/auth/overview.mdx).
<br />
## Advanced topics
There are many more advanced features that hasura provides to handle custom business logic, security, caching,
monitoring and much more. Below we will be going through some of these commonly used features.
### Actions
Actions are a convenient and secure way to connect to REST APIs to achieve any business logic you may need, directly
from your GraphQL API. In the simplest of terms actions send a POST request to your endpoint with a payload.
It is useful in cases like needing to validate user, process or enrich some data, call another API, or log a user in.
With Actions you can connect to a REST endpoint which can be your own custom server, a public API, or a serverless
function. You can also import your existing rest endpoints as actions, from an OpenAPI spec.
[Read more about actions](/actions/overview.mdx)
### Event Triggers
Hasura Event triggers are a way to automate asynchronous logic when changes are made in a connected database.
Event Triggers can be configured to activate when there is an INSERT, UPDATE or DELETE event in a table. Additionally,
you can manually trigger an event through a button set up in the Hasura Console. One example use case of Event triggers
is sending an email to a newly signed up user.
[Read more about Event Triggers](/event-triggers/overview.mdx)
### Caching
Hasura provides a caching layer that can be used to cache the response of a GraphQL query. This can help reduce the
number of requests to your datasources and improve the performance of your application.
You have full control over the cache lifetime and can choose to force the cache to refresh when you need to. With Hasura
Caching, your application is highly-optimized and performant, reducing the load on your servers.
[Read more about caching](/caching/overview.mdx)
### Observability
Hasura Observability is a set of tools that help you monitor and debug your Hasura instance. With Observability, you can
check on the performance of your GraphQL API, debug errors, and get insights into your GraphQL API usage. We provide
detailed error reporting, usage summaries, detailed metrics of graphql operations like query latency, request count, and
error rate.
We offer integrations with popular monitoring tools like Datadog, Prometheus, and OpenTelemetry and you can quickly get
set up with these tools using one of our guides.
[Read more about Observability](/observability/overview.mdx)
### Setting limits on API
Setting some limits on API requests can help prevent API performance issues caused by malicious or poorly implemented
queries, and helps preventing attacks like Denial of Service. You can easily set up various kinds of limits on your API
using the hasura console. There are multiple type of API limits offered by Hasura.
- <b>Rate limits</b> restricts number of GraphQL operations per minute.
- <b>Depth limits</b> restricts a GraphQL operation based on its depth, preventing deeply nested queries.
- <b>Node limits</b> restricts a GraphQL operation based on the number of nodes. This helps in limiting the number of different
pieces of related data to be fetched.
- <b>Time limits</b> restricts the time that a GraphQL operation is allowed to take.
- <b>Batch Limits</b> restricts the number of GraphQL operations in a batched request.
[Read more about API limits](/security/api-limits.mdx)
## Next steps
For a full hands-on tour of Hasura, check out our
[30-Minute Hasura Basics Tutorial](https://hasura.io/learn/graphql/hasura/introduction/).

View File

@ -0,0 +1,339 @@
---
description: Building a federated API across data sources
title: Building a federated API
sidebar_label: Building a Data Federation with Hasura
keywords:
- hasura
- graphql
- data
- federation
- resource
sidebar_position: 3
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Player from '@site/src/components/Player';
import Thumbnail from '@site/src/components/Thumbnail';
import GraphiQLIDE from '@site/src/components/GraphiQLIDE';
# Building a federated API across data sources with Hasura
## Introduction
Hasura's data federation capabilities allow you to compose data from different sources that reside in independent data
stores but are semantically related.
Hasura creates a single GraphQL schema from multiple data sources thereby making the data access process self-serve,
allowing you to query, mutate or federate in real-time and stream data across services without writing any custom code.
<Thumbnail src="/img/data-federation/hasura_data_federation.png" alt="Hasura Data Federation API" />
Following are the possibilities Hasura offers for connecting different data sources under the same instance and defining
relationships among them:
- [Database to database relationships](/schema/postgres/remote-relationships/remote-source-relationships.mdx): Hasura
allows you to stitch data from multiple database sources together.
- [Database to remote-schema relationships](/schema/postgres/remote-relationships/remote-schema-relationships.mdx) and
[vice versa](/remote-schemas/remote-relationships/remote-schema-db-relationships.mdx): A remote graphl server can be
connected to a database under a single GraphQL API.
- [Remote Schema to remote schema relationships](/remote-schemas/remote-relationships/remote-schema-db-relationships.mdx):
Multiple remote GraphQL sources (for eg: remote Graphql API servers like Spotify, Auth0) can be stitched together
under a single GrahQL API.
- [Database to Actions](/schema/postgres/remote-relationships/action-relationships.mdx): A REST API exposed as a Hasura
[Action](/actions/overview.mdx) can be connected to other data sources under the same hood.
## Sample use case
For this example, we'll be stitching 3 different database instances to create a federated API using Hasura.
<Thumbnail src="/img/data-federation/hasura_data_federation_ecommerce_app.png" alt="E-Commerce app schema" />
Consider an E-commerce app with 4 tables distributed among 3 different databases, where `users` related information
resides in the first db, the Order Management System (`orders` and `order_items`) lies in the second and the Inventory
(`products`) lies in the third.
## Step 1: Set up databases
:::info Note
We will be using Hasura Console in the next few steps, which is a web app to set up Hasura by just making some clicks!
If you landed on this doc and do not have the Hasura console open, we recommend you to go through one of the quickstart
guides [here](/getting-started/overview.mdx) first.
Also assuming that you are connecting to an already running Postgres database instance. The steps are going to be the
same for other databases for the most part. But if required, you can reference [this](/databases/overview.mdx) section
if you are stuck.
:::
- To keep this simple, we'll create 3 Postgres databases using [Neon](https://neon.tech/) from Hasura console. Checkout
the [list](/databases/overview.mdx#supported-databases) of supported databases by Hasura.
- Head over to `Data` -> `Data Manager` -> `Connect New Database` and click on `Connect Neon Database`. This will create
a free Postgres database instance and add it as a data source to Hasura.
- Paste the following raw SQL in the SQL tab to set up the initial schema and seed data for the respective database/s.
Make sure the `Track this` is checked while running the SQL commands to make sure the created tables are tracked by
Hasura.
- Repeat the process for the other databases as well.
<Tabs groupId="user-preference" className="api-tabs">
<TabItem value="users" label="Users">
```sql
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET escape_string_warning = off;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE public.users (
id uuid DEFAULT public.uuid_generate_v1() NOT NULL,
name text NOT NULL,
email text NOT NULL UNIQUE,
password text NOT NULL,
address text NOT NULL
);
ALTER TABLE ONLY public.users
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
INSERT INTO public.users (id, name, email, password, address) VALUES ('7cf0a66c-65b7-11ed-b904-fb49f034fbbb', 'Sean', 'seandemo@hasura.io.com', 'SeanUsesHasura', '14 Fornham Road, Bury St. Edmunds, IP32 6AH');
INSERT INTO public.users (id, name, email, password, address) VALUES ('82001336-65b7-11ed-b905-7fa26a16d198', 'Rob', 'robdemo@hasura.io.com', 'RobUsesHasura', '8 Ilderton Crescent, Seaton Delaval, NE25 0FH');
INSERT INTO public.users (id, name, email, password, address) VALUES ('86d5fba0-65b7-11ed-b906-afb985970e2e', 'Marion', 'mariondemo@hasura.io.com', 'MarionUsesHasura', '25 Kirkfields, Baildon, BD17 6HY');
INSERT INTO public.users (id, name, email, password, address) VALUES ('8dea1160-65b7-11ed-b907-e3c5123cb650', 'Sandeep', 'sandeepdemo@hasura.io.com', 'SandeepUsesHasura', 'Six Bricks, Smithy Banks, Holmrook, CA19 1TP');
INSERT INTO public.users (id, name, email, password, address) VALUES ('9bd9d300-65b7-11ed-b908-571fef22d2ba', 'Abby', 'abbydemo@hasura.io.com', 'AbbyUsesHasura', '3 Eardley Place, Grange Farm, MK8 0PN');
```
</TabItem>
<TabItem value="orders" label="Orders">
```sql
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET escape_string_warning = off;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE public.orders (
id uuid DEFAULT public.uuid_generate_v1() NOT NULL,
user_id uuid NOT NULL,
order_date timestamp with time zone NOT NULL
);
CREATE TABLE public.order_items (
id uuid DEFAULT public.uuid_generate_v1() NOT NULL,
order_id uuid NOT NULL,
product_id uuid NOT NULL,
quantity int NOT NULL
);
ALTER TABLE ONLY public.orders
ADD CONSTRAINT orders_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.order_items
ADD CONSTRAINT order_items_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.order_items
ADD CONSTRAINT order_items_order_id_foreign FOREIGN KEY (order_id) REFERENCES public.orders(id);
INSERT INTO public.orders (id, user_id, order_date) VALUES ('452230eb-8955-4bfb-add3-37d89326f136',
'7cf0a66c-65b7-11ed-b904-fb49f034fbbb', '2023-03-23T07:02:29.581199+00:00'); INSERT INTO public.orders (id, user_id,
order_date) VALUES ('51aec62a-0be9-4950-89ce-ca8babe5104f', '82001336-65b7-11ed-b905-7fa26a16d198',
'2022-03-23T07:02:29.581199+00:00'); INSERT INTO public.orders (id, user_id, order_date) VALUES
('87487a6d-0560-4305-aad3-70a75231cf17', '86d5fba0-65b7-11ed-b906-afb985970e2e', '2023-03-24T07:02:29.581199+00:00');
INSERT INTO public.orders (id, user_id, order_date) VALUES ('34f64d2c-7897-48eb-b5be-4886808b7826',
'86d5fba0-65b7-11ed-b906-afb985970e2e', '2019-01-12T07:02:29.581199+00:00'); INSERT INTO public.orders (id, user_id,
order_date) VALUES ('a9968bb0-1cf2-4ebd-b2b9-3e9b7ac7891e', '8dea1160-65b7-11ed-b907-e3c5123cb650',
'2021-03-14T07:02:29.581199+00:00'); INSERT INTO public.orders (id, user_id, order_date) VALUES
('7e5155cf-9543-49c5-aee7-fa2296bf65d5', '9bd9d300-65b7-11ed-b908-571fef22d2ba', '2021-11-19T07:02:29.581199+00:00');
INSERT INTO public.order_items (id, order_id, product_id, quantity) VALUES ('6b5b09de-b2bc-4f81-907f-eea8ef58bcd4',
'452230eb-8955-4bfb-add3-37d89326f136', '5a053b73-8196-4a88-aea2-2deb3404995c', 2); INSERT INTO public.order_items (id,
order_id, product_id, quantity) VALUES ('dd676acb-2917-4e64-acd7-bff2b85ff8a0', '452230eb-8955-4bfb-add3-37d89326f136',
'89604b69-f1d0-4da9-bb18-9bb002cba5bd', 1); INSERT INTO public.order_items (id, order_id, product_id, quantity) VALUES
('37f63337-f3c8-4b08-b129-1e0a16117cb6', '51aec62a-0be9-4950-89ce-ca8babe5104f', '8286d91e-63df-4202-a367-a43da1e5d52a',
5); INSERT INTO public.order_items (id, order_id, product_id, quantity) VALUES ('34b97156-aedb-44c4-8a3e-36df05ec9f70',
'51aec62a-0be9-4950-89ce-ca8babe5104f', 'a84f5433-511e-4a50-9770-11ed97dfdc93', 1); INSERT INTO public.order_items (id,
order_id, product_id, quantity) VALUES ('2a9db620-0f5d-439a-b8f9-89b5a90a743b', '87487a6d-0560-4305-aad3-70a75231cf17',
'35480a9a-0651-4d79-89e5-03447ca127fc', 1); INSERT INTO public.order_items (id, order_id, product_id, quantity) VALUES
('21f85fcc-e1af-47ca-a706-daa0aeeafac1', '34f64d2c-7897-48eb-b5be-4886808b7826', '35480a9a-0651-4d79-89e5-03447ca127fc',
8); INSERT INTO public.order_items (id, order_id, product_id, quantity) VALUES ('fabc21f0-487d-41dc-8339-cbd8d4910ba2',
'34f64d2c-7897-48eb-b5be-4886808b7826', '41182cd6-c312-4fba-b5d3-125b805c9313', 6); INSERT INTO public.order_items (id,
order_id, product_id, quantity) VALUES ('4b6528fb-359c-4d39-96eb-c4bcb1282411', 'a9968bb0-1cf2-4ebd-b2b9-3e9b7ac7891e',
'35480a9a-0651-4d79-89e5-03447ca127fc', 10); INSERT INTO public.order_items (id, order_id, product_id, quantity) VALUES
('617f628b-b6f2-4b40-bcd2-c2b041611398', '7e5155cf-9543-49c5-aee7-fa2296bf65d5', '41182cd6-c312-4fba-b5d3-125b805c9313',
2);
```
</TabItem>
<TabItem value="products" label="Products">
```sql
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET escape_string_warning = off;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE public.products (
id uuid DEFAULT public.uuid_generate_v1() NOT NULL,
manufacturer text NOT NULL,
stock int NOT NULL
);
ALTER TABLE ONLY public.products
ADD CONSTRAINT products_pkey PRIMARY KEY (id);
INSERT INTO public.products (id, manufacturer, stock) VALUES ('5a053b73-8196-4a88-aea2-2deb3404995c', 'Ivy', 10);
INSERT INTO public.products (id, manufacturer, stock) VALUES ('89604b69-f1d0-4da9-bb18-9bb002cba5bd', 'Brigham', 12);
INSERT INTO public.products (id, manufacturer, stock) VALUES ('8286d91e-63df-4202-a367-a43da1e5d52a', 'Arn', 100);
INSERT INTO public.products (id, manufacturer, stock) VALUES ('a84f5433-511e-4a50-9770-11ed97dfdc93', 'Karly', 420);
INSERT INTO public.products (id, manufacturer, stock) VALUES ('35480a9a-0651-4d79-89e5-03447ca127fc', 'Peter', 2);
INSERT INTO public.products (id, manufacturer, stock) VALUES ('41182cd6-c312-4fba-b5d3-125b805c9313', 'Atlas', 25);
```
</TabItem>
</Tabs>
<Player src="/img/data-federation/setup_databases.webm" showControls autoPlay={false} loop={false} />
## Step 2: Add Relationships
[Relationships](https://hasura.io/docs/latest/schema/postgres/remote-relationships/index/) are a way to join data across
different data sources. With remote joins, the join, authorization, and consistency checks of added sources all happen
at the Hasura layer via metadata. Think of it as foreign keys but neither limited within a single data source nor
necessary a one-one entity.
In our example, we'll be adding a many-one relationship (`order_items` -> `order`) within our Order Management System
and a one-one relationship (`users` <-> `orders` and `order_items` <-> `products` respectively) among remote databases.
- For adding the suggested relationship within the database:
- Head to `Data` tab -> `orders` table -> `Relationships` -> `Suggested Array Relationships`
- Hit `Add` next to the suggested array relationship of `order_items` <-> `orders`.
- Similarly, head to `Data` tab -> `order_items` table -> `Relationships` -> `Suggested Object Relationships`
- Hit `Add` next to the suggested object relationship of `order_items` <-> `orders`.
<Player src="/img/data-federation/add_relationships.webm" showControls autoPlay={false} loop={false} />
- For adding remote database relationships:
- Head to `Data` tab -> `users` table -> `Relationships` -> `Remote Database Relationships`
- Define an Object relationship between `users` and `orders` with reference fields as `id` and `user_id` respectively.
Let's name this relationship `user_orders`. Hit `Save`.
- Similarly, in the `order_items` table, define an Object relationship between `order_items` and `products` with
reference fields as `product_id` and `id` respectively. Let's name this `order_items_products`. Hit `Save`.
<Player src="/img/data-federation/add_remote_relationships.webm" showControls autoPlay={false} loop={false} />
## Step 3: Add Permissions
Hasura's fine-grained access control system allows you to specify which users can access which data, ensuring that your
application is secure and robust. [Read more](/auth/overview.mdx) on Authentication and Authorization in Hasura.
One of the primary features of Hasura is that it provides Role Based Access Control (RBAC) with granularity i.e. it
enables users to create roles and define custom granular row/column level properties on them.
In our case:
- `users` table contains sensitive information like the `password` field which ideally should only be exposed to the
`admin` role. Column-level permissions i.e. restricted access to columns based on the role defined comes in handy
here.
- Also, a user should not be allowed to read other users' data in the same table. Row-level permissions can be used here
by defining custom checks based on the role.
To implement this:
- Head over to the `users` table -> `Permissions` tab. By default, an `admin` role is already present with access to all
CRUD operations. Let's create a custom role called `user` and define only `select` level permissions for them.
- Click on the edit icon against the `select` tab:
- Define `Row select permissions` with a custom check `{"email":{"_eq":"x-hasura-user-email"}}`. For every request
made, this will ensure to check the email passed as `x-hasura-user-email` header and return rows specific to only
those emails.
- Define `Column Level Permissions` by selecting only columns that should be accessible to the user. These will be
`name`, `email`, and `address` in our case.
- Click on `Save Permissions`.
<Player src="/img/data-federation/add_permissions.webm" showControls autoPlay={false} loop={false} />
## Step 4: Explore GraphQL API
Voila! Your data federated API is ready to use.
Let's say you wanna query a specific user from `users` with a known email, their `orders`, `order items`, and the
details of the `products` in those orders in a single request. Hasura enables you to query this stitched data from
different sources in a single GraphQL API call.
Head over to the `API` tab and test out the following GraphQL query:
<GraphiQLIDE
query={`query DataFederationUseCase {
users(where: {email: {_eq: "seandemo@hasura.io.com"}}) {
id
email
user_orders {
order_date
id
order_items {
product_id
quantity
order_items_products {
stock
manufacturer
}
}
}
}
}
`}
response={`{
"data": {
"users": [
{
"id": "7cf0a66c-65b7-11ed-b904-fb49f034fbbb",
"email": "seandemo@hasura.io.com",
"user_orders": {
"order_date": "2023-03-23T07:02:29.581199+00:00",
"id": "452230eb-8955-4bfb-add3-37d89326f136",
"order_items": [
{
"product_id": "5a053b73-8196-4a88-aea2-2deb3404995c",
"quantity": 2,
"order_items_products": {
"stock": 10,
"manufacturer": "Ivy"
}
},
{
"product_id": "89604b69-f1d0-4da9-bb18-9bb002cba5bd",
"quantity": 1,
"order_items_products": {
"stock": 12,
"manufacturer": "Brigham"
}
}
]
}
}
]
}
}`}
/>
:::info Note
If `x-hasura-admin-secret` is present in `Request Headers` under `API` tab, the role will default to `admin`. You can
read more on admin access [here](https://hasura.io/docs/latest/auth/authentication/admin-secret-access/#admin-secret).
:::
## Advanced topics
### Remote Schemas as a data source
- Hasura enables you to write queries and mutations to disparate sources (eg.: remote GraphQL API), all from your single
Hasura endpoint.
- With respect to the above example, if the inventory management system was a remote Graphql API server, Hasura will
make it possible to stitch this API by defining remote relationships with other data sources.
- [Read more](https://hasura.io/docs/latest/remote-schemas/quickstart/) on how to go about adding a remote schema as a
data source.
### REST Endpoints as a data source
- Actions are a way to extend Hasura's schema with REST APIs. You need to provide the schema for the API and the REST
API endpoint which is then called for resolving the result.
- [Read more](https://hasura.io/docs/latest/actions/quickstart/) on how to set up a REST endpoint as an action.
### Caching
- Hasura Cloud and Enterprise Edition provide support for caching query responses, to improve performance for queries
that are executed frequently. This includes Actions and queries against Remote Schemas.
- Cached responses are stored for a period of time in a LRU (least-recently used) cache, and removed from the cache as
needed based on usage.
- [Read more](https://hasura.io/docs/latest/queries/response-caching/) on Hasura Query Response Caching.

View File

@ -0,0 +1,427 @@
---
description: Building a GraphQL backend for an application using Hasura
title: Building a GraphQL backend for an application
sidebar_label: Building a GraphQL backend with Hasura
keywords:
- hasura
- graphql
- backend
- tutorial
- resource
sidebar_position: 2
---
import Thumbnail from '@site/src/components/Thumbnail';
# Building a GraphQL backend for an application with Hasura
## Introduction
The Hasura GraphQL Engine is a blazing-fast GraphQL server that gives you instant, real-time GraphQL APIs over many
popular databases and other data sources. Using Hasura you can build a powerful GraphQL backend that makes it easy to
build scalable and secure applications just by connecting a database and defining a schema.
## Example
This guide will outline the steps required to set up a Hasura GraphQL backend for a todos app as an example.
Our `todos app` will have the following features:
- Users can create personal to-dos
- User can mark their to-dos as completed
- Users can view public to-dos
- View a list of currently online users using the app
:::info Note
We will be using the Hasura Console in the next few steps, which is a web app to setup Hasura by just making some
clicks! If you landed on this doc and do not have the Hasura console open, we recommend you to go through one of the
quickstart guides [here](/getting-started/overview.mdx) first.
Hasura Console is a web-based graphical user interface (GUI) tool that allows users to interact with and manage their
Hasura GraphQL APIs. It provides an intuitive interface for exploring the schema, creating tables, modifying data, and
testing queries, among other things.
:::
## Step 1: Connect Database
To set up Hasura as a GraphQL backend, the first step is to establish a connection between a database and Hasura. Hasura
provides support for a wide range of databases, which can be found in the
[supported databases](/databases/overview.mdx/#supported-databases) section.
To connect your database you should navigate to the `Data` -> `Manage` -> `Connect Database` ->
`Connect Existing Database` tab in Hasura Console and enter the `Database Display Name` , `Database URL` and click the
`Connect Database` button.
<Thumbnail src="/img/resources/hasura-as-gql-backend/data-api-connect-db.gif" alt="Cloud Dashboard" width="800px" />
If you dont have a database to connect, you can get started with a free <a href="https://neon.tech/" >Neon</a> Postgres
database by navigating to the `Data` -> `Manage` -> `Connect Database` -> `Connect New Database` tab in Hasura Console
and clicking on the `Connect Neon Database` button.
After successfully connecting the database you can select `View Database` in the notification to view your database.
## Step 2: Data modeling
Data modeling is a crucial step in building a backend for your application. Its important to define your schema based on
the backend logic of your app. This involves considering the relationships between your data and how it will be stored
and retrieved.
In the `todos app` example, we have two main models in this app: `users` and `todos`, each with its own set of
properties.
The final model looks like the following:
![Schema Todo app](https://graphql-engine-cdn.hasura.io/learn-hasura/assets/graphql-hasura/voyager-schema.png)
As we create tables using the Console or directly on postgres, the Hasura GraphQL Engine automatically creates GraphQL
APIs to access the data.
### Step 2.1: Create Tables
Hasura makes this easy by providing a schema builder that allows you to create tables and relationships visually.
After you have connected a database, to create a table, click on the `Data` tab in the Hasura Console, and then click
the `Create Table` button. You'll be prompted to enter a table name and the columns you want to include in the table.
You can also specify relationships between tables, which will be used to generate GraphQL queries and mutations
automatically.
For the todo-app let's get started by creating the `users` table.
The `users` table will have the following columns:
- `id` (type Text and Unique),
- `name` (type Text),
- `created_at` (type Timestamp and default now())
- `last_seen` (type Timestamp and nullable)
The columns are associated with properties of users. The `last_seen` column is used to store the latest timestamp of
when the user was online.
![Create table users](https://graphql-engine-cdn.hasura.io/learn-hasura/assets/graphql-hasura/create-table-users.png)
Once you are done, click on `Add Table` button to create the table.
Similarly we can create a `todos` table having following items:
- `id` (type Integer (auto-increment)),
- `title` (type Text),
- `is_completed` (type Boolean and default false)
- `is_public` (type Boolean and default false)
- `created_at` (type Timestamp and default now())
- `user_id` (type Text)
## Step 3: Explore GraphQL API
To query data using Hasura, you can use any GraphQL client that supports HTTP requests, such as GraphQL Playground,
Postman, or Insomnia.
Hasura gives you instant GraphQL APIs over tables and views existing in your database. For example, for the todos app,
you can start exploring the GraphQL API for the users table. We are going to use GraphiQL to explore the API.
GraphiQL is the GraphQL integrated development environment (IDE). It's a powerful tool to interact with the API.
You can access GraphiQL by heading over to the `API` tab.
Here's how to explore the GraphQL APIs for the todos app example:
### Step 3.1: Mutation {#mutation}
We can add a user using a [GraphQL Mutation](https://hasura.io/learn/graphql/intro-graphql/graphql-queries/). Copy the
following code into the GraphiQL interface.
```graphql
mutation {
insert_users(objects: [{ id: "1", name: "user_1" }]) {
affected_rows
}
}
```
Click on the `Play` button on the GraphiQL interface to execute the query.
You should get a response looking something like this:
<Thumbnail src="/img/resources/hasura-as-gql-backend/Mutation.png" alt="Cloud Dashboard" width="800px" />
Great! You have just successfully run a mutation on the `users` table that you just created.
**Tip**: You can use the `Explorer` on the GraphiQL interface to generate the mutation in a few clicks.
### Step 3.2: Query {#query}
Here is how to [query](https://hasura.io/docs/latest/queries/index/) the data that we just inserted.
```graphql
query {
users {
id
name
created_at
}
}
```
You should get a response that looks something like this:
<Thumbnail src="/img/resources/hasura-as-gql-backend/query.png" alt="Cloud Dashboard" width="800px" />
Note that some columns like `created_at` have default values, even though you did not insert them during the mutation.
### Step 3.3: Subscription {#subscription}
If a client subscribes to a specific query using a GraphQL subscription, it will receive real-time updates whenever
there are changes to the data returned by that query. This means that if a new record is added to the database that
matches the subscribed query, the client will immediately receive a notification about the new data, without having to
make a new API request.
For the `todos app`, we can run a [subscription](https://hasura.io/docs/latest/subscriptions/index/) over `users` table
to watch for changes to the table in realtime without having to query every time.
```graphql
subscription {
users {
id
name
created_at
}
}
```
In a new tab, try adding more records into your `users` table and see the records being updated in the running
subscription.
## Step 4: Create Relationships
Relationships are the connections between different tables in a relational database. By defining relationships between
tables in a database schema, you can access data across tables using GraphQL queries without having to write complex SQL
join statements.
GraphQL schema relationships can be either
- **object relationships (one-to-one)**: In a one-to-one relationship, one object is linked to only one other object of
another type. For our `todo app` example, a single `to-do` entry corresponds only to only one user. may have one
profile picture. In this case, the `to-do` object type would have a single field that references the `user` object
type. This type of relationship is useful when you have a strict one-to-one mapping between objects.
- **array relationships (one-to-many)**: In a in a one-to-many relationship, one object is linked to multiple objects of
another type. For our `todo app`example, a `user` may have many `to-dos` In this case, the `user` object type would
have a field that returns a list of `to-do` objects. This type of relationship is useful when you have multiple
related objects of the same type.
### Step 4.1: Create Foreign Key
A foreign key is a type of database constraint that ensures that the values in a column or set of columns in one table
match the values in another table's primary key. In other words, it creates a link between two tables that is enforced
by the database.
For the `todos app` in the `todos` table, the value of `user_id` column must be ideally present in the `id` column of
`users` table. Otherwise, it would result in inconsistent data.
Here we can define a foreign key called `user_id` column in `todos`. For this head over to `Console` -> `DATA` ->
`todos` -> `Modify` page.
![Todos Modify Page](https://graphql-engine-cdn.hasura.io/learn-hasura/assets/graphql-hasura/todos-modify-page.png)
Scroll down to `Foreign Keys` section at the bottom and click on `Add`.
![user_id foreign key](https://graphql-engine-cdn.hasura.io/learn-hasura/assets/graphql-hasura/user-id-foreign-key.png)
- Select the Reference table as `users`
- Choose the From column as `user_id` and To column as `id`
We are enforcing that the `user_id` column of `todos` table must be one of the values of `id` in `users` table.
Click on `Save` to create the foreign key.
Great! Now you have ensured data consistency.
### Step 4.2: Create Relationship
Now that the foreign key constraint is created, Hasura Console automatically suggests relationships based on that.
Head over to `Relationships` tab under `todos` table and you should see a suggested relationship like below:
![Todos Relationships Page](https://graphql-engine-cdn.hasura.io/learn-hasura/assets/graphql-hasura/todos-relationship-page.png)
Click on `Add` in the suggested object relationship.
Enter the relationship name as `user` (already pre-filled) and click on `Save`.
![User Object Relationship](https://graphql-engine-cdn.hasura.io/learn-hasura/assets/graphql-hasura/todos-relationship-user.png)
A relationship has now been established between todos and users table. We can now run queries with nesting.
```graphql
query {
todos {
id
title
user {
id
name
}
}
}
```
You can see the response in the following format:
<Thumbnail src="/img/resources/hasura-as-gql-backend/nested-query.png" alt="Cloud Dashboard" width="800px" />
Great! Now you know the basics of setting up Hasura Graphql Backend and using the Instantly Generated GraphQL APIs.
## Step 5: Set Authorization rules
Hasura provides a robust access control system that enables users to specify which users can access specific data,
ensuring that their application is secure. Hasura offers Role-Based Access Control (RBAC) with granular row/column level
properties. Access control rules help in restricting querying on a table based on certain conditions.
In this realtime `todos app` example, certain columns in tables do not need to be exposed to the user. The aim of the
app is to allow users to manage their own todos only but should be able to view all the public todos.
To implement this in Hasura, head over to the `Permissions` tab under `todos` table to add relevant permissions. We want
to allow logged-in users creating a new todo entry to only specify the `is_public` and `title` columns.
- In the enter new role textbox, type in `user`
- Click on edit (pencil) icon for `insert` permissions. This would open up a section below, which lets you configure
custom checks and allow columns.
- In the custom check, choose the following condition
```json
{ "user_id": { "_eq": "X-Hasura-User-Id" } }
```
Under "Column insert permissions", select the `title` and `is_public` columns. Below "Column presets", select `user_id`
from `from session variable` mapping to `X-HASURA-USER-ID`.
<Thumbnail src="/img/resources/hasura-as-gql-backend/insert-permission.png" alt="Cloud Dashboard" width="800px" />
:::info Session variables are key-value pairs returned from the authentication service for each request. When a user
makes a request, the session token maps to a `USER-ID`. This `USER-ID` can be used in permission to show that inserts
into a table are only allowed if the `user_id` column has a value equal to that of `USER-ID`, the session variable. :::
Click on `Save Permissions`.
Similarly you can setup `Select`, `Update` and `Delete`permissions and permissions for the `todos table`.
## Advanced topics
Up until now, we have addressed the data-modeling and relationships part of constructing a backend. However, Hasura
offers numerous sophisticated functionalities for handling custom business logic, security, caching, monitoring, and a
variety of other features. In the following section, we will discuss some of the very useful topics briefly.
### Actions
Actions are a way to execute arbitrary code or scripts in response to a GraphQL mutation. With actions, you can extend
your GraphQL API beyond simple database queries and mutations, and incorporate business logic, third-party APIs, and
other external services.
To add an action to send todo notification via the Hasura console, follow these steps:
Open the Hasura console and navigate to the `Actions` tab. Click on the `Create` button to create a new action. In the
Action Definition section, define a GraphQL mutation with the required input parameters for the action.
<Thumbnail
src="/img/actions/actions-quickstart_step-1_console_2-17-0.png"
alt="Click create for new Action"
className="no-shadow"
width="800px"
/>
For example, if you want to add a new todo and send a notification to the user who created it, you can define a mutation
like this:
```graphql
mutation AddTodoAndNotify($todo: String!, $userId: Int!) {
insert_todos(objects: { todo: $todo, user_id: $userId }) {
affected_rows
}
send_notification(name: "john_doe", message: "A new todo has been added")
}
```
In the `Webhook (HTTP/S) Handler` section, enter the `URL` of the endpoint that will receive the action request and
process it.
In the `Configure REST Connectors` section, modify the payload if necessary to send the required data to the endpoint.
Click the `Create Action` button to save the action and test it by going to the API Explorer and selecting the
corresponding mutation. Provide the input parameters and execute the mutation to trigger the action.
### Event triggers
Event triggers are a way to execute a GraphQL mutation in response to a database event such as an insert, update, or
delete. With event triggers, you can automate workflows and perform real-time processing of data changes.
For our `todos app` we can set up an event trigger to send welcome email for new user who signs up. We can do this by
creating an Event Trigger that calls out to a webhook whenever a new user is inserted into the users table. The webhook
payload will contain the user's email address, and we can use this in the endpoint which we create to send them the
welcome email.
Navigate to the `Event` tab in the Console and click the `Create` button while on the `Event Triggers` tab in the left
navigation.
<Thumbnail
src="/img/event-triggers/event-triggers_main-screen_2-19-0.png"
alt="Click create for new Action"
width="800px"
/>
On the Event Trigger creation page, input the name of the trigger, `send_welcome_email`, and select the database, schema
and table that the trigger will be listening to. In this case we'll be listening to the `users` table for an INSERT
event.
In the `Webhook (HTTP/S) Handler` section, enter the `URL` of the endpoint to be called when the event is triggered.
Click `Create Event Trigger` button to save the event trigger and test it by going to the API Explorer and selecting the
corresponding mutation. Provide the input parameters and execute the mutation to trigger the action.
<Thumbnail
src="/img/event-triggers/event-triggers_create-event-trigger_2-19-0.png"
alt="Click create for new Action"
width="800px"
/>
### Authentication
Hasura authentication is a feature that allows users to authenticate with Hasura and access data through GraphQL
queries. The authentication process involves two main components: authentication providers and authorization rules.
Authentication providers are services that handle the authentication process for Hasura. Hasura supports several
authentication providers, including email/password, social media logins (such as Google, Facebook, and GitHub), and
third-party authentication services (such as Auth0 and Firebase).
In case of `todos app` example, we have a users table in the database. The data of customers signing up can go into this
table. With Hasura, it is very easy to set up JWT based authentication.
Here's what the flow for a login with JWT looks like.
<Thumbnail src="/img/resources/hasura-as-gql-backend/auth-jwt-mode.png" alt="JWT auth" width="800px" />
The REST API call to your custom Node.js server can be queried via GraphQL on the same endpoint that Hasura provides.
Hasura Actions can be used to extend the auto-generated GraphQL types. Actions are a way to extend Hasuras schema with
custom business logic using custom queries and mutations.
Custom mutation for signup would look very simple:
```graphql
mutation {
signup(name: "user_1", id: "1", password: "password") {
id
token
}
}
```
The server generates JWT token using a custom secret shared with Hasura and returns the token back to the client after
inserting the user into the database.
On the other hand, you can also make use of Auth providers like Auth0, Firebase, Cognito which works well with
[Hasura's Auth system](/auth/authentication/index.mdx).
## Conclusion
Using Hasura as a GraphQL backend can simplify the process of building complex applications. By defining your data
schema, adding business logic, and securing your API with Hasura, you can focus on building a great user experience.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB