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
4
docs/docs/resources/use-case/_category_.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"label": "Hasura Use Cases",
|
||||
"position": 3
|
||||
}
|
183
docs/docs/resources/use-case/api-gateway.mdx
Normal 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.
|
398
docs/docs/resources/use-case/data-api.mdx
Normal 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/).
|
339
docs/docs/resources/use-case/data-federation.mdx
Normal 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.
|
427
docs/docs/resources/use-case/gql-backend.mdx
Normal 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 Hasura’s 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.
|
BIN
docs/static/img/data-federation/add_permissions.webm
vendored
Normal file
BIN
docs/static/img/data-federation/add_relationships.webm
vendored
Normal file
BIN
docs/static/img/data-federation/add_remote_relationships.webm
vendored
Normal file
BIN
docs/static/img/data-federation/hasura_data_federation.png
vendored
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
docs/static/img/data-federation/hasura_data_federation_ecommerce_app.png
vendored
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
docs/static/img/data-federation/setup_databases.webm
vendored
Normal file
BIN
docs/static/img/getting-started/Erd-remote-schemas.png
vendored
Normal file
After Width: | Height: | Size: 205 KiB |
BIN
docs/static/img/getting-started/action-definition.png
vendored
Normal file
After Width: | Height: | Size: 198 KiB |
BIN
docs/static/img/getting-started/env-var-remote-schema.png
vendored
Normal file
After Width: | Height: | Size: 153 KiB |
BIN
docs/static/img/getting-started/hasura-use-case/data-api-connect-db.webm
vendored
Normal file
BIN
docs/static/img/getting-started/hasura-use-case/data-api-intro-gif.gif
vendored
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
docs/static/img/getting-started/hasura-use-case/data-api-make-mutation.webm
vendored
Normal file
BIN
docs/static/img/getting-started/hasura-use-case/data-api-make-query.webm
vendored
Normal file
BIN
docs/static/img/getting-started/hasura-use-case/data-api-set-relationship.webm
vendored
Normal file
BIN
docs/static/img/getting-started/hasura-use-case/data-api-subscription.webm
vendored
Normal file
BIN
docs/static/img/getting-started/hasura-use-case/data-api-track-tables.webm
vendored
Normal file
BIN
docs/static/img/getting-started/hasura-use-case/set-permissions.webm
vendored
Normal file
BIN
docs/static/img/getting-started/remote-schema-for-gateway.png
vendored
Normal file
After Width: | Height: | Size: 135 KiB |
BIN
docs/static/img/getting-started/remote-schema-query.png
vendored
Normal file
After Width: | Height: | Size: 210 KiB |
BIN
docs/static/img/resources/hasura-as-gql-backend/Mutation.png
vendored
Normal file
After Width: | Height: | Size: 218 KiB |
BIN
docs/static/img/resources/hasura-as-gql-backend/auth-jwt-mode.png
vendored
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
docs/static/img/resources/hasura-as-gql-backend/cloud_dashboard.png
vendored
Normal file
After Width: | Height: | Size: 140 KiB |
BIN
docs/static/img/resources/hasura-as-gql-backend/data-api-connect-db.gif
vendored
Normal file
After Width: | Height: | Size: 3.7 MiB |
BIN
docs/static/img/resources/hasura-as-gql-backend/insert-permission.png
vendored
Normal file
After Width: | Height: | Size: 230 KiB |
BIN
docs/static/img/resources/hasura-as-gql-backend/nested-query.png
vendored
Normal file
After Width: | Height: | Size: 214 KiB |
BIN
docs/static/img/resources/hasura-as-gql-backend/query.png
vendored
Normal file
After Width: | Height: | Size: 197 KiB |