2018-11-23 16:02:46 +03:00
|
|
|
|
Custom business logic
|
|
|
|
|
=====================
|
|
|
|
|
|
2018-12-03 15:12:24 +03:00
|
|
|
|
.. contents:: Table of contents
|
|
|
|
|
:backlinks: none
|
|
|
|
|
:depth: 1
|
|
|
|
|
:local:
|
|
|
|
|
|
2018-11-23 16:02:46 +03:00
|
|
|
|
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:
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- **Pre-CRUD**: :ref:`remote-schemas`
|
|
|
|
|
- **Post-CRUD**: :ref:`event-triggers`
|
|
|
|
|
- :ref:`derived-data`
|
|
|
|
|
|
2020-08-25 19:21:21 +03:00
|
|
|
|
.. thumbnail:: /img/graphql/core/business-logic/custom-business-logic.png
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
|
|
|
|
.. _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:
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
|
|
|
|
- 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 engine’s API
|
2018-11-23 16:02:46 +03:00
|
|
|
|
- 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
|
2018-11-23 16:02:46 +03:00
|
|
|
|
schema using the console. Here's a reference architecture diagram for such a setup:
|
|
|
|
|
|
2020-08-25 19:21:21 +03:00
|
|
|
|
.. thumbnail:: /img/graphql/core/schema/schema-stitching-v1-arch-diagram.png
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
|
|
|
|
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
|
2018-11-23 16:02:46 +03:00
|
|
|
|
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
|
2018-11-23 16:02:46 +03:00
|
|
|
|
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
|
2018-11-23 16:02:46 +03:00
|
|
|
|
subscriptions to listen to updates from your webhook via Postgres.
|
|
|
|
|
|
2020-08-25 19:21:21 +03:00
|
|
|
|
.. thumbnail:: /img/graphql/core/event-triggers/database-event-triggers.png
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
|
|
|
|
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
|
2018-11-23 16:02:46 +03:00
|
|
|
|
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*).
|
2018-11-23 16:02:46 +03:00
|
|
|
|
|
|
|
|
|
For more information on how to do this, please see :doc:`../queries/derived-data`.
|