Easily restore your project to a previous version with our new Instant One-click Backup Recovery

How to build a multi-tenant real-estate platform with Hygraph

In this article, we’ll walk through a build for a multi-tenant real-estate platform, and you’ll learn how to create and add content to models along the way.
Kevin Kimani

Kevin Kimani

Apr 28, 2023
How to build a multi-tenant real-estate platform with Hygraph

In this article, we’ll walk through a build for a multi-tenant real-estate platform, and you’ll learn how to create and add content to models along the way. You’ll also explore more advanced concepts like setting roles and permissions for a project team member and how to set Permanent Auth Tokens (PATs) to protect your content endpoint.

#What is Hygraph and how is it used?

Hygraph is a headless CMS that focuses on content federation. Its native support for GraphQL enables you to easily deliver ambitious applications at scale.

Hygraph’s API-first approach lends itself to a variety of use cases, including:

  • Knowledge management. Hygraph provides you with a schema builder for structuring data in a reusable and centralized manner. You can deliver that data to consumers programmatically via an API or through the Hygraph Content Studio.

  • Content federation. All your end users can access content from a single location instead of having several fragmented data sources. That way, your users always have access to updated information, and you can avoid tedious data migration.

  • Websites and SEO. With features like structured content, SEO, and asset management, you can optimize your site’s content for multiple devices. Edit your website’s metadata to fit your specific needs, leading to a better SEO score.

  • Multi-tenancy. Run a single instance of the software on a server and serve multiple clients. Multi-tenant applications allow you to configure them to serve your specific needs without changing their core code structure. That translates into easy configuration, lower costs, and no maintenance fees.

This tutorial focuses on that last use case, multi-tenancy.

#Building a multi-tenant real-estate platform with Hygraph

Before you move on with the tutorial, make sure you’re prepared with the following prerequisites:

  • A Hygraph account that’s subscribed to the Enterprise plan.

  • Node.js and npm installed.

  • A web browser.

  • Three email accounts: one account to create the project, and two more to act as project invitees.

Project overview

Here’s a high-level view of what you’ll create:

undefined

  • My Real Estate is the name of the project.

  • agentOne Listing and agentTwo Listing are the different models that belong to the My Real Estate project.

  • agentOne and agentTwo are the custom roles you’ll create for the project.
  • The arrows indicate the permissions assigned to each role.

  • Each role will have access to a specific model and cannot access any other model.

Creating a project and models

Log into your Hygraph account and click Add project.

undefined

On the New project pop-up, enter My Real Estate as the project name, provide a project description, and select a region where you want your content to be stored.

undefined

Click Add project to navigate to your dashboard. On the sidebar, click Schema to open the schema editor.

undefined

Click + Add to create a new agentOne Listing. This model will store the real estate listings for one agent. Leave the API ID and Plural API ID with their default values. You can add an optional description for this model.

undefined

Click Add Model to create the model.

To add a field to the model, select one of the field types from the schema editor. The agentOne Listing model has the following fields:

  • Name. Stores the name of the listing.
  • Location. Stores the location of the listing.
  • Price. Stores the listing’s price.
  • Image. Stores the listing’s image.
  • Description. Stores the listing’s description.

To create the Name field, select the Single line text field type. Set Display name to Name. On the Validations tab, make the field required.

undefined

Repeat the process to create other fields. The following table shows the types and validations for other fields:

FieldField TypeValidation
LocationSingle line textMake field required
PriceFloatMake field required
ImageAsset pickerMake field required
DescriptionMulti line textMake field required

After completing this process, your UI should look like this:

undefined

Repeat the process for creating the model and create a new model called agentTwo Listing with the same fields as the agentOne Listing model.

Please note that you’re creating two different models, as each agent will only have access to its corresponding model.

Adding content to the models

Now that you have two models set up, go ahead and add content to them. Select Content from the project dashboard sidebar to open the content editor.

undefined

First, let’s add content for the agentOne Listing model. Make sure that you have it selected and click + Add entry.

undefined

Once you’ve filled out all the required details, click Save & publish. When prompted, confirm whether you want to also publish the referenced documents. Select the image checkbox to confirm and select Save and publish.

Repeat the process above to add content for the agentTwo Listing model. You can add as many content entries as you want, but this tutorial only covers the use of one content entry per model.

To test whether the content was successfully published, select API playground from the project dashboard and test the query below:

{
agentOneListings {
name
price
location
image {
url
}
description
}
agentTwoListings{
name
price
location
image {
url
}
description
}
}

Your output should be similar to this:

undefined

Setting up roles and permissions for users

Within the Hygraph CMS, roles help to ensure data safety by dictating the data a user can view and the actions they are allowed to perform on that data. Hygraph offers default system roles but also gives you the freedom to implement your own custom roles.

Note that custom roles are only available in enterprise plans.

To configure custom roles so that each agent can only access its own content models, select Project settings > Roles & Permissions from the project dashboard sidebar.

undefined

Select + Add custom role.

Set agentOne Role as the name of the custom role and provide an optional description of the role. Then click Add to create the custom role.

undefined

Open the custom role details page by clicking on the name of the role. On the "agentOne Role" details page, select "+ Add permission".

undefined

On the Add permission page, select agentOne Listing as the model that this role applies to. Select all the checkboxes to give this role the permission to create, update, delete, read, publish, unpublish, and view versions of the agentOne Listing model. Click Add to save the permissions.

undefined

On the details page for agentOne Role, select Edit permissions to open the Update role page. On this page, under Management API Permissions, select the following checkboxes:

  • Create new entries
  • Update existing non published entries
  • Update published entries
  • Publish non published entries
  • Delete existing entries

Users assigned the agentOne Role can now perform the actions described by these permissions. Do not deselect the already-selected options! These options allow users assigned to this role to read the existing environments, models, enumerations, fields, and entries.

undefined

The next step is to assign members to this role. On the "agentOne Role" details page, click the "Assign members" button and select "Add team members" on the page that opens.

undefined

Here, enter the email address of the team member you want to invite and click the "Add" button. Confirm that you want to add the member to the role by clicking the "Assign 1 member" button on the confirmation page. An invitation email will be sent to the provided email address.

undefined

Repeat this process to create a custom role called agentTwo Role for the agentTwo Listing model.

To confirm that the set roles and permissions are working as expected, accept the agentOne Role invite and confirm that you can only access the agentOne Listing model. You can also confirm that you are only able to perform actions permitted by the permissions you set earlier.

Enabling API access

Hygraph allows you to either enable full public access to your API endpoint or protect it with a permanent auth token. Let’s walk through setting up permanent auth tokens as each agent will have its own unique token for querying its respective content models.

To implement permanent auth tokens, navigate to Project settings > API Access > Permanent Auth Tokens. Click + Add token to set up the first token.

undefined

Name your token agentOne Token and click Add & configure permissions.

undefined

This takes you to the agentOne Token details page. Select + Add permission.

undefined

Choose the agentOne Listing model, select all the permissions, and click Add.

undefined

Finally, click + Add permission again, this time selecting the Asset model. Select all the permissions and click Add. This permission on the assets model allows the agent to query assets, such as the real-estate listing image.

Repeat this process to create a permanent auth token for the agentTwo Listing model as well.

Take note of these two tokens for agentOne and agentTwo; you’ll use them in the frontend to query the Hygraph GraphQL endpoint.

Setting up the frontend project

Implement the frontend using React, a JavaScript library for building user interfaces. Navigate to a directory of your choice and run the following commands in the terminal to create a React app using Vite:

npm create vite@latest my-real-estate -- --template react
cd my-real-estate
npm install

To install the dependencies you’ll use in this project, run the following command:

npm install @apollo/client graphql bootstrap react-bootstrap

The dependencies include the following:

  • @apollo/client. Queries the Hygraph GraphQL endpoint.
  • graphql. Parses GraphQL queries.
  • bootstrap and react-bootstrap. Style the webpage.

Once you’ve successfully installed the dependencies, open the src/main.jsx file and replace the existing code with the following:

import 'bootstrap/dist/css/bootstrap.min.css'
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { HttpLink, ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
const httpLink = new HttpLink({
uri: '<your-hygraph-content-api-endpoint>',
});
const authLink = setContext((_, { headers }) => {
// set the auth token
const token = '<your-agentOne-token>'
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
ReactDOM.createRoot(document.getElementById('root')).render(
<ApolloProvider client={client}>
<React.StrictMode>
<App />
</React.StrictMode>
</ApolloProvider>,
)

In the code above, you initialized an ApolloClient instance, attached the Bearer token, and connected the client to the React app.

Remember to replace <your-agentOne-token> with your actual agentOne token from the Hygraph dashboard. You should also replace <your-hygraph-content-api-endpoint> with the value for your Hygraph Content API endpoint. You can get this value from Project settings > API Access > Endpoints.

Next, open the src/App.jsx file and replace the existing code with the following:

import { gql, useQuery } from '@apollo/client';
import { Container, Card } from 'react-bootstrap';
const GET_LISTINGS = gql`
query GetListings {
agentOneListings {
id
name
price
image {
url
}
description
location
createdAt
}
}
`;
function App() {
const { loading, error, data } = useQuery(GET_LISTINGS);
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<Container className='d-flex flex-column align-items-center'>
<h2>My Real Estate Listings</h2>
{
data.agentOneListings.map(listing => (
<Card style={{maxWidth: '50rem'}} key={listing.id}>
<Card.Img variant='top' src={listing.image.url} />
<Card.Body>
<Card.Title className='h2'>{listing.name}</Card.Title>
<Card.Text className='h6'>{listing.location}</Card.Text>
<Card.Text className='h5'>Price: ${listing.price}</Card.Text>
<Card.Text>
{listing.description}
</Card.Text>
</Card.Body>
<Card.Footer>
{
`Created on: ${new Date(listing.createdAt).toLocaleString()}`
}
</Card.Footer>
</Card>
))
}
</Container>
)
}
export default App

In the code above, you created a GraphQL query to get agentOne's listings and used the useQuery hook to request the data from the Hygraph Content API endpoint. You then looped the data using the map() function and displayed it using the Bootstrap Card component.

To confirm that the application is working as expected, start the development server with the command npm run dev and open your browser on http://localhost:5173/. You should get output similar to the following image:

undefined

To view agentTwo's listings, open the src/main.jsx file and replace the token's value with agentTwo's permanent auth token. Then open the src/App.jsx file and replace the existing code with the following:

import { gql, useQuery } from '@apollo/client';
import { Container, Card } from 'react-bootstrap';
const GET_LISTINGS = gql`
query GetListings {
agentTwoListings {
id
name
price
image {
url
}
description
location
createdAt
}
}
`;
function App() {
const { loading, error, data } = useQuery(GET_LISTINGS);
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
return (
<Container className='d-flex flex-column align-items-center'>
<h2>My Real Estate Listings</h2>
{
data.agentTwoListings.map(listing => (
<Card style={{maxWidth: '50rem'}} key={listing.id}>
<Card.Img variant='top' src={listing.image.url} />
<Card.Body>
<Card.Title className='h2'>{listing.name}</Card.Title>
<Card.Text className='h6'>{listing.location}</Card.Text>
<Card.Text className='h5'>Price: ${listing.price}</Card.Text>
<Card.Text>
{listing.description}
</Card.Text>
</Card.Body>
<Card.Footer>
{
`Created on: ${new Date(listing.createdAt).toLocaleString()}`
}
</Card.Footer>
</Card>
))
}
</Container>
)
}
export default App

In the code above, note that you only changed the query to fetch agentTwo's listings and the map function to loop through agentTwo's listings. Open your browser, and you should get a result similar to the following image:

undefined

To confirm that agentOne cannot query agentTwo's real estate listings, change the value of token in the src/main.jsx file to agentOne's permanent auth token. Do not modify the src/App.jsx file, so that it will attempt to query for agentTwo's real estate listings with agentOne's token. You should get an Error! not allowed message in the browser.

#Conclusion

In this article, you learned about Hygraph’s use cases as well as some of its basic concepts, such as creating a model and populating the model with data. You also learned about Hygraph's more advanced concepts, such as setting up custom roles and permissions to limit what data your project team members can view and what actions they can perform. Finally, you explored how to project your project endpoint so that only authorized personnel can query data and perform other actions through the endpoint.

To learn more about what you can achieve with Hygraph, check out the official documentation.

The Complete Guide on CMS Multi-Tenancy

Learn how to unlock the full potential of multi-tenant CMS solutions.

Download the guide

Blog Author

Kevin Kimani

Kevin Kimani

Kevin Kimani is a passionate developer and technical writer who enjoys explaining complicated concepts in a simple way.