graphql-engine/docs/graphql/core/business-logic/index.rst.wip

107 lines
4.6 KiB
Plaintext
Raw Normal View History

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
2019-09-11 10:17:14 +03:00
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
2019-09-11 10:17:14 +03:00
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
2019-09-11 10:17:14 +03:00
GraphQL engines 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
2019-09-11 10:17:14 +03:00
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
---------------------------------------------
2019-09-11 10:17:14 +03:00
"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.
2019-09-11 10:17:14 +03:00
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
2019-09-11 10:17:14 +03:00
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
2019-09-11 10:17:14 +03:00
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
2019-09-11 10:17:14 +03:00
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`.