-
Notifications
You must be signed in to change notification settings - Fork 2.8k
allow custom mutations through actions #3042
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
76 commits
Select commit
Hold shift + click to select a range
b3ac563
basic doc for actions
0x777 8946ba7
wip docs
tirumaraiselvan 05684e8
wip: custom_types, sync and async actions
0x777 61072b1
switch to graphql-parser-hs on github
0x777 04b863c
update docs
tirumaraiselvan afb4ac9
metadata import/export
0x777 a7d72ac
webhook calls are now supported
0x777 ca4fd66
relationships in sync actions
0x777 4462284
revert to lts-13 and bump graphql-parser-hs commit
0x777 e0570a5
lower the lts version so that the Cabal version matches that of the b…
0x777 4bc8106
disable -Werr on this branch
0x777 c86dcc4
initialise.sql is now in sync with the migration file
0x777 cb05dd1
fix metadata tests
0x777 b925752
allow specifying arguments of actions
0x777 ea0f8f7
fix blacklist check on check_build_worthiness job
arvi3411301 a40b68e
track custom_types and actions related tables
0x777 c33372a
handlers are now triggered on async actions
0x777 1ba45d1
clean up annotated relationship related code
0x777 2559837
default to pgjson unless a field is involved in relationships, for ge…
0x777 1c9819a
temporary fix for async subscriptions
0x777 aa02af1
use 'true' for action filter for non admin role
0x777 0c7b499
fix create_action_permission sql query
0x777 5a5ad19
drop permissions when dropping an action
0x777 1f6adac
add a hdb_role view (and relationships) to fetch all roles in the system
0x777 6944f42
fix retrieving action permission information from catalog
0x777 4e81961
fix error message when action webhook returns 'errors'
rakeshkky 483ef36
rename 'webhook' key in action definition to 'handler'
rakeshkky 7d736c2
allow templating actions wehook URLs with env vars
rakeshkky 3fcc908
add 'update_action' /v1/query type
rakeshkky f58b887
Merge branch 'master' into actions
rakeshkky 74593f5
Merge branch 'master' into actions
rakeshkky 3a6f444
Merge branch 'master' into actions
rakeshkky a6b5a8c
allow forwarding client headers by setting `forward_client_headers` i…
rakeshkky 8180674
add 'headers' configuration in action definition
rakeshkky 694791b
handle webhook error response based on status codes
rakeshkky 0865aac
support array relationships for custom types
rakeshkky d4668bf
temp: ignore errors on warnings
tirumaraiselvan 9344d08
Merge branch 'master' into actions
rakeshkky f5c8071
Merge branch 'master' into actions
rakeshkky 8323c30
implement single row mutation, see https://github.com/hasura/graphql-…
rakeshkky 596fe2a
single row mutation: rename 'pk_columns' -> 'columns' and no-op refactor
rakeshkky 78ab464
use top level primary key inputs for delete_by_pk & account select pe…
rakeshkky b2de9c0
use only REST semantics to resolve the webhook response
rakeshkky fb25f8e
Merge branch 'master' into actions
rakeshkky 116ac5b
remove warnings
rakeshkky a2423bf
Merge branch 'master' into actions
rakeshkky 487ee82
use 'pk_columns' instead of 'columns' for update_by_pk input
rakeshkky 7368748
add python basic tests for single row mutations
rakeshkky be07e04
refactor code building actions' cache & validate presence of actions …
rakeshkky 4e58372
add action context (name) in webhook payload
rakeshkky 99aab8a
Merge branch 'master' into actions
rakeshkky b02474b
avoid '_0_root.base' hack & add async result accessible check
rakeshkky 1becb1b
Merge branch 'master' into actions
rakeshkky e5b49c5
small no-op refactor in schema/cache.hs
rakeshkky 8234626
clean nulls, empty arrays for actions, custom types in export metadata
rakeshkky 7c2be6d
async action mutation returns only the UUID of the action
rakeshkky b1fff1c
Merge branch 'master' into actions
rakeshkky a9ef569
unit tests for URL template parser
rakeshkky ecbd40b
Basic sync actions python tests
rakeshkky 2e439c2
no-op refactor
rakeshkky d3ffcef
fix output in async query & add async tests
rakeshkky 5268b2a
add admin secret header in async actions python test
rakeshkky baf40ff
remove comments in resolve/action.hs
rakeshkky a0771e0
incorporate review suggestion by @0x777
rakeshkky a3e2805
document async action architecture in Resolve/Action.hs file
rakeshkky 5b2de9a
remove few commented code
rakeshkky 06b35e6
Merge branch 'master' into actions
rakeshkky c96dd6e
remove commented code from GraphQL/Context.hs & update graphql-parser…
rakeshkky 57f71e8
Merge branch 'master' into actions
rakeshkky 2e92e3a
remove a non exhaustive pattern matches
rakeshkky c3557ea
support actions returning array of objects
rakeshkky 20e23a1
tests for list type response actions
rakeshkky e32545e
update docs with actions and custom types metadata API reference
rakeshkky 9222cae
Merge branch 'master' into actions
rakeshkky 8a07237
Merge branch 'master' into actions
0x777 12dc26e
update actions python tests as per #f8e1330
rakeshkky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| Action handlers | ||
| =============== | ||
|
|
||
|
|
||
| .. contents:: Table of contents | ||
| :backlinks: none | ||
| :depth: 1 | ||
| :local: | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| Actions need to be backed by custom business logic. This business logic can be defined in different types of handlers. | ||
|
|
||
|
|
||
| HTTP handler | ||
| ------------ | ||
|
|
||
| WIP | ||
|
|
||
| Postgres functions | ||
| ------------------ | ||
|
|
||
| WIP | ||
|
|
||
| Postgres PLV8 | ||
| ---- | ||
|
|
||
| Similar to postgres functions but in nodejs. | ||
|
|
||
|
|
||
| Managing and deploying action handlers | ||
| -------------------------------------- | ||
|
|
||
| HTTP handlers in serverless functions, micoservice APIs etc | ||
|
|
||
| Postgres functions as migrations, etc |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| Async Actions | ||
| ============= | ||
|
|
||
|
|
||
| .. contents:: Table of contents | ||
| :backlinks: none | ||
| :depth: 1 | ||
| :local: | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| Sometimes you may not want to wait for an action to complete (say if the business logic takes a long time). In such cases you can create an **asynchronous** action, which returns an ``action_id`` immediately to the client before contacting the webhook. | ||
|
|
||
| If you mark an action as **asynchronous**, graphql-engine also generates a query and a subscription field for the action so that you can query/subscribe to its status. In the above example, let's say ``place_order`` is an asnychronous action, your client code looks something like this: | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
| mutation place_order($order_input: place_order_input!) { | ||
| place_order(input: $order_input) { | ||
| action_id | ||
| } | ||
| } | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
| subscription order_status($action_id: uuid!) { | ||
| place_order(action_id: $action_id) { | ||
| order { | ||
| id | ||
| payment_url | ||
| total_amount | ||
| discount | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| Getting Started with Actions | ||
| ============================ | ||
|
|
||
|
|
||
| .. contents:: Table of contents | ||
| :backlinks: none | ||
| :depth: 1 | ||
| :local: | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| Let's say you are building an ecommerce application where you need to provide a mutation for placing an 'order', ``place_order``. | ||
|
|
||
| Example | ||
| ------- | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| First, you will need to first define the input types for this mutation in the console: | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
| enum payment_method { | ||
| stripe | ||
| paypal | ||
| } | ||
|
|
||
| input type place_order_input { | ||
| selected_payment_mode payment_method! | ||
| items [order_item_input!]! | ||
| address_id uuid! | ||
| coupon_code String | ||
| } | ||
|
|
||
| input order_item_input { | ||
| skuId uuid! | ||
| quantity Int! | ||
| } | ||
|
|
||
| type place_order_response { | ||
| order_id uuid! | ||
| } | ||
|
|
||
| You will then define an action called ``place_order`` with ``place_order_input`` as the **input** type, ``place_order_response`` as the **output** type. | ||
|
|
||
| Once you have the action setup, you'll have to define the permissions for the role for which you want to allow this action. For all such roles, this action will be exposed as a mutation. The client can then execute this mutation as follows: | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
| mutation place_order($order_input: place_order_input!) { | ||
| place_order(input: $order_input) { | ||
| response { | ||
| order_id | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| But how is this action executed? An action can be linked to different types of handlers (see: :doc:`Action handlers <action-handlers>`) . In this example, let's use a HTTP handler which will be invoked when this action is called by the client. The logic of this handler could look something like this: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| def place_order(payload): | ||
| input_args = payload['input'] | ||
| session_variables = payload['session_variables'] | ||
| order_id = validate_and_insert_order(input_args, session_variables) # some business logic code | ||
| return {"order_id": order_id} | ||
|
|
||
| And that's it. You have created your first action! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| Actions | ||
| ======= | ||
|
|
||
| .. contents:: Table of contents | ||
| :backlinks: none | ||
| :depth: 1 | ||
| :local: | ||
|
|
||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| Actions are user defined mutations with custom business logic. Actions can be added to Hasura to handle various use cases such as data validation, data enrichment and other complex business logic. | ||
|
|
||
| When the permissions system isn't enough to specify the required constraints, you would typically add such mutation through a remote schema. However actions can handle these use cases better because of the following reasons: | ||
|
|
||
| 1. No need to write a remote schema. Actions can be executed in ordinary webhooks or postgres itself. | ||
|
|
||
| 2. Return graphql-engine's types without writing any extra code. You might want to return the new "state" after a mutation. | ||
|
|
||
| 3. Can be executed asynchronously for building powerful event-driven apps. | ||
|
|
||
| Architecture Diagram | ||
| -------------------- | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
|
|
||
| Learn more | ||
| ---------- | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 1 | ||
| :titlesonly: | ||
|
|
||
| Getting started <getting-started> | ||
| Input types <input-types> | ||
| Response types <response-types> | ||
| Action handlers <action-handlers> | ||
| Async actions <async-actions> | ||
| Sample use cases <use-cases> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| Action Input Types | ||
| ================== | ||
|
|
||
| .. contents:: Table of contents | ||
| :backlinks: none | ||
| :depth: 1 | ||
| :local: | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| Reference for creating different input types. | ||
|
|
||
|
|
||
| Scalar Input Types | ||
| ------------------ | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
| enum payment_method { | ||
| stripe | ||
| paytm | ||
| } | ||
|
|
||
|
|
||
| Object Input Types | ||
| ------------------ | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
| input type place_order_input { | ||
| selected_payment_mode payment_method! | ||
| items [order_item_input!]! | ||
| address_id uuid! | ||
| coupon_code String | ||
| } | ||
|
|
||
| input order_item_input { | ||
| skuId uuid! | ||
| quantity Int! | ||
| } | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| Action Response Types | ||
| ===================== | ||
|
|
||
|
|
||
| .. contents:: Table of contents | ||
| :backlinks: none | ||
| :depth: 1 | ||
| :local: | ||
|
|
||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| You can return different types of responses when an action is executed. | ||
|
|
||
| Basic Response | ||
| -------------- | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
|
|
||
| mutation place_order($order_input: place_order_input!) { | ||
| place_order(input: $order_input) { | ||
| response { | ||
| order_id | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Complex response with relationships | ||
| ----------------------------------- | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
| mutation place_order($order_input: place_order_input!) { | ||
| place_order(input: $order_input) { | ||
| response { | ||
| order { | ||
| id | ||
| payment_url | ||
| total_amount | ||
| discount | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| You can fetch relationships of the ``order`` like you would when you query the ``order`` table. Thus with actions you can write the minimum needed code that is needed to validate the mutation and still not lose out on the powerful query fields that graphql-engine generates. | ||
|
|
||
| Async response | ||
| -------------- | ||
|
|
||
| WORK IN PROGRESS | ||
|
|
||
| .. code-block:: graphql | ||
|
|
||
| mutation place_order($order_input: place_order_input!) { | ||
| place_order(input: $order_input) { | ||
| action_id | ||
| } | ||
| } | ||
|
|
||
| Where ``action_id`` is a unique id generated for every async action that has been performed. | ||
|
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love this feature! In trying this, I noticed that when running an async mutation, I am seeing
idbeing made available through the GraphQL schema when attempting to subscribe to my action - as opposed to theaction_idstated here.