mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-22 15:01:39 +03:00
107 lines
4.6 KiB
Plaintext
107 lines
4.6 KiB
Plaintext
Custom business logic
|
||
=====================
|
||
|
||
.. contents:: Table of contents
|
||
:backlinks: none
|
||
:depth: 1
|
||
:local:
|
||
|
||
For the backends of most apps, you may have to implement custom business logic to complement the CRUD and
|
||
real-time API provided by GraphQL engine. Depending on the nature of the use case and its position vis-a-vis
|
||
GraphQL engine/Postgres, different avenues are recommended for introducing such business logic in your app's backend:
|
||
|
||
|
||
- **Pre-CRUD**: :ref:`remote-schemas`
|
||
- **Post-CRUD**: :ref:`event-triggers`
|
||
- :ref:`derived-data`
|
||
|
||
.. thumbnail:: /img/graphql/core/business-logic/custom-business-logic.png
|
||
|
||
.. _remote-schemas:
|
||
|
||
Custom resolvers in remote schemas
|
||
----------------------------------
|
||
|
||
Merging remote schemas is ideal for adding "pre-CRUD" business logic (*logic to be run before you invoke
|
||
GraphQL engine's GraphQL API to insert/modify data in Postgres*) or custom business logic that is not part of
|
||
your GraphQL engine schema. Here are some use-cases where remote schemas are ideal:
|
||
|
||
- Customizing mutations (e.g. running validations before inserts)
|
||
- Supporting features like payments, etc. and providing a consistent interface to access them i.e. behind the
|
||
GraphQL engine’s API
|
||
- Fetching disparate data from other sources (e.g. from a weather API or another database)
|
||
|
||
To support these kinds of business logic, a custom GraphQL schema with resolvers that implement said business
|
||
logic is needed (*see link below for boilerplates*). This remote schema can then be merged with GraphQL engine's
|
||
schema using the console. Here's a reference architecture diagram for such a setup:
|
||
|
||
.. thumbnail:: /img/graphql/core/schema/schema-stitching-v1-arch-diagram.png
|
||
|
||
For more details, links to boilerplates for custom GraphQL servers, etc. please head to :doc:`../remote-schemas/index`.
|
||
|
||
.. _event-triggers:
|
||
|
||
Asynchronous business logic / Events triggers
|
||
---------------------------------------------
|
||
|
||
"post-CRUD" business logic (*follow up logic to be run after GraphQL engine's GraphQL API has been used to insert
|
||
or modify data in Postgres*) typically tends to be asynchronous, stateless and is triggered on changes to data
|
||
relevant to each use case. E.g. for every new user in your database, you may want to send out a notification. This
|
||
business logic is triggered for every new row in your ``users`` table.
|
||
|
||
GraphQL engine comes with built-in events triggers on tables in the Postgres database. These triggers capture events
|
||
on specified tables and then invoke configured webhooks, which contain your business logic.
|
||
|
||
If your business logic is stateful, it can even store its state back in the Postgres instance configured to work
|
||
with GraphQL engine, allowing your frontend app to offer a reactive user experience, where the app uses GraphQL
|
||
subscriptions to listen to updates from your webhook via Postgres.
|
||
|
||
.. thumbnail:: /img/graphql/core/event-triggers/database-event-triggers.png
|
||
|
||
Event triggers are ideal for use cases such as the following:
|
||
|
||
- Notifications: Trigger push notifications and emails based on database events
|
||
|
||
- ETL: Transform and load data into external data-stores.
|
||
|
||
- E.g. transform data from Postgres and populate an Algolia index when a product is inserted, updated or deleted.
|
||
|
||
- Long-running business logic:
|
||
|
||
- Provision some infrastructure
|
||
- Process multimedia files
|
||
- Background jobs
|
||
|
||
- Cache/CDN purge: invalidate/update entries in your cache/CDN when the underlying data in Postgres changes.
|
||
|
||
For more information on event triggers and how to set them up, please see :doc:`../event-triggers/index`.
|
||
|
||
.. _derived-data:
|
||
|
||
Derived data / Data transformations
|
||
-----------------------------------
|
||
|
||
For some use cases, you may want to transform your data in Postgres or run some predetermined function on it to
|
||
derive another dataset (*that will be queried using GraphQL engine*). E.g. let's say you store each user's location
|
||
data in the database as a ``point`` type. You are interested in calculating the distance (*say the haversine distance*)
|
||
between each set of two users i.e. you want this derived dataset:
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
|
||
* - user_id_1
|
||
- user_id_2
|
||
- distance between users
|
||
* - 12
|
||
- 23
|
||
- 10.50
|
||
* - 12
|
||
- 47
|
||
- 76.00
|
||
|
||
The easiest way to handle these kinds of use cases is to create a view, which encapsulates your business logic
|
||
(*in our example, calculating the distance between any two users*), and query your derived/transformed data as you
|
||
would a table using GraphQL engine (*with permissions defined explicitly for your view if needed*).
|
||
|
||
For more information on how to do this, please see :doc:`../queries/derived-data`.
|