Package: cypartagraphqlsubscriptionstools
Graphene CypartaGraphqlSubscriptionsToolsIntroductionA CypartaGraphqlSubscriptionsTools implementation for Graphene + Django built using Django Channels +reactive programming in python (RxPY)
. Provides support for model creation, mutation and deletion,and get data with websocket or path list of events name for subscriptions .libirary support Both WebSocket Protocol graphql-transport-ws and graphql-wsfor more info use full link :https://wundergraph.com/blog/quirks_of_graphql_subscriptions_sse_websockets_hasura_apollo_federation_supergraph#graphql-subscriptions-over-websockets:-subscription-transport-ws-vs-graphql-wslibirary use async for more beast performanceCypartaGraphqlSubscriptionsTools FeaturesReal-time GraphQL Subscriptions:Enables real-time communication between GraphQL clients and servers using WebSocket connections.Support for Django Models:Integrates seamlessly with Django models, providing subscriptions for model creation, update, and deletion events.Django Subscription Model Mixin:Powerful mixin for Django models to enable real-time GraphQL subscriptions on instance lifecycle events.Dynamic Subscription Management:Flexible mechanism for managing subscriptions dynamically using parameters likesubscripeandid.WebSocket Protocol Support:Supports bothgraphql-transport-wsandgraphql-wsfor compatibility with various GraphQL clients.Async Implementation:Leverages asynchronous programming for enhanced performance and suitability for high-concurrency applications.Custom Event Support:Allows creation of custom events and subscriptions, providing flexibility for handling events beyond Django signals.Observable and Reactive Programming:Utilizesrxpyfor handling observables and reactive programming, enabling application of various operations on subscription streams.Multi-Subscription Support:Supports multiple subscriptions concurrently, allowing clients to subscribe to multiple events or models simultaneously.Easy Integration with Graphene:Seamless integration with the Graphene library for easy definition and management of GraphQL subscriptions.Ping Mechanism:Includes a ping mechanism to keep WebSocket connections alive and maintain communication between clients and servers.WebSocket Group Management:Provides functions for dynamically registering and unregistering WebSocket groups for organized subscription handling.In-memory Channel Layer Support:Supports an in-memory Channel Layer for development environments without the need for a dedicated Redis instance.Customizable Routing:Allows customization of WebSocket routing in Django channels, making it adaptable to various project structures.Compatibility with Django Lifecycle:Works seamlessly with thedjango_lifecyclelibrary to leverage Django model lifecycle events.InstallationInstallCypartaGraphqlSubscriptionsTools$pipinstalldjango_lifecycle
$pipinstallCypartaGraphqlSubscriptionsToolsAddCypartaGraphqlSubscriptionsToolstoINSTALLED_APPS:# your_project/settings.pyINSTALLED_APPS=[# ...'CypartaGraphqlSubscriptionsTools']Add Django Channels to your project (see:Django Channels installation docs) and set upChannel Layers. If you don't want to set up a Redis instance in your dev environment yet, you can use the in-memory Channel Layer:# your_project/settings.pyCHANNEL_LAYERS={"default":{"BACKEND":"channels.layers.InMemoryChannelLayer"}}AddCypartaGraphqlSubscriptionsConsumerto yourrouting.pyfile.# your_project/routing.pyfromchannels.routingimportProtocolTypeRouter,URLRouterfromdjango.urlsimportpathfromCypartaGraphqlSubscriptionsTools.consumersimportCypartaGraphqlSubscriptionsConsumerapplication=ProtocolTypeRouter({"websocket":URLRouter([path('graphql/',CypartaGraphqlSubscriptionsConsumer)]),})Define your subscriptions and connect them to your project schema#your_project/schema.pyimportgraphenefromyour_app.graphql.subscriptionsimportYourSubscriptionclassQuery(graphene.ObjectType):base=graphene.String()classSubscription(YourSubscription):passschema=graphene.Schema(query=Query,subscription=Subscription)Django Subscription Model MixinThe Django Subscription Model Mixin is a powerful tool that seamlessly integrates with Django models to enable real-time GraphQL subscriptions when model instances are created, updated, or deleted. This mixin leverages thedjango_lifecyclelibrary for managing model lifecycle events and theCypartaGraphqlSubscriptionsToolslibrary for triggering GraphQL subscriptions.UsageInherit from theCypartaSubscriptionModelMixinin Your Django Model:# your_project/models.pyfromCypartaGraphqlSubscriptionsTools.mixinsimportCypartaSubscriptionModelMixinclassYourModel(CypartaSubscriptionModelMixin,models.Model):# Your model fields and methods go hereReplaceYourModelwith the actual name of your model. This mixin provides hooks for triggering subscriptions on model lifecycle events, such as creation, update, and deletion.Defining SubscriptionsSubscriptions in Graphene are defined as normalObjectType's. Each subscription field resolver must return an observable which emits values matching the field's type.A simple hello world subscription (which returns the value"hello world!"every 3 seconds) could be defined as follows:importgraphenefromrximportObservableclassSubscription(graphene.ObjectType):hello=graphene.String()defresolve_hello(root,info):returnObservable.interval(3000)\.map(lambdai:"hello world!")Responding to Model EventsEach subscription that you define will receive a anConsumerofCypartaGraphqlSubscriptionsConsumer's as therootparameter, which will subscripe or cancel bydetect_register_group_statusfunction  .Model Created SubscriptionsThis code snippet demonstrates how to implement GraphQL subscriptions for Django models using the CypartaGraphqlSubscriptionsTools library. In this example, a subscription namedmymodelcreatedis defined to trigger events whenever a new instance of theMyModelDjango model is created. Thesubscripeparameter is introduced, allowing for dynamic subscription management by providing a boolean value (Trueto subscribe,Falseto cancel subscription).Code Explanation-GraphQL Type Definition: The code defines a GraphQL type YourModelType using graphene and graphene_django.types.DjangoObjectType for the MyModel Django model.-Subscription Definition: The Subscription class extends graphene.ObjectType and includes a subscription field namedget_my_model. This field is associated with the MyModelType and includes the subscripe parameter to manage subscription status.-Subscription Resolver Logic: The resolve_my_model_created function handles the resolution logic for theget_my_modelsubscription. It dynamically extracts requested fields from the GraphQL query using info.field_nodes and filters for the relevant fields. The event name is constructed based on the model name and the event type ({model_name}Created). The resolution logic is then delegated to thedetect_register_group_statusfunction.Event Triggering: The event is triggered whenever a new instance ofMyModelis created, leveraging the signals provided bydjango_lifecycle.importgraphenefromgraphene_django.typesimportDjangoObjectTypefromCypartaGraphqlSubscriptionsTools.eventsimportCREATEDfromyour_app.modelsimportMyModelclassYourModelType(DjangoObjectType)classMeta:model=MyModelclassSubscription(graphene.ObjectType):get_my_model=graphene.Field(MyModelType,subscripe=graphene.Boolean())# Resolve function for handling 'get_my_model' based on 'subscripe'defresolve_get_my_model(root,info,subscripe):requested_fields=[field.name.valueforfieldininfo.field_nodes[0].selection_set.selections]model_name=get_model_name_instance(MyModelType)returnasync_to_sync(root.detect_register_group_status)([f'{model_name}Created'],subscripe,requested_fields)Model Updated SubscriptionsYou can also filter events based on a subscription's arguments. For example, here's a subscription that fires whenever a model is updated:importgraphenefromgraphene_django.typesimportDjangoObjectTypefromCypartaGraphqlSubscriptionsTools.eventsimportUPDATEDfromyour_app.modelsimportMyModelclassYourModelType(DjangoObjectType)classMeta:model=MyModelclassSubscription(graphene.ObjectType):my_model_updated=graphene.Field(MyModelType,id=graphene.String(),subscripe=graphene.Boolean())# Resolve function for handling 'my_model_updated' based on 'subscripe' and 'id'defresolve_my_model_updated(root,info,subscripe,id):model_name=get_model_name_instance(MyModelType)returnasync_to_sync(root.detect_register_group_status)([f'{model_name}Updated.{id}'],subscripe)Model Created Updated Deleted SubscriptionsYou can also filter events based on a subscription's arguments. For example, here's a subscription that fires whenever a model is updated:importgraphenefromgraphene_django.typesimportDjangoObjectTypefromCypartaGraphqlSubscriptionsTools.eventsimportUPDATEDfromyour_app.modelsimportMyModelclassYourModelType(DjangoObjectType)classMeta:model=MyModelclassSubscription(graphene.ObjectType):my_model_created_update_delete=graphene.Field(MyModelType,subscripe=graphene.Boolean(),id=graphene.String())# Resolve function for handling create, update, delete operations based on 'subscripe' and 'id'defresolve_my_model_created_update_delete(root,info,subscripe,id):requested_fields=[field.name.valueforfieldininfo.field_nodes[0].selection_set.selections]model_name=get_model_name_instance(MyModelType)groups=[f'{model_name}Created',f'{model_name}Updated.{id}',f'{model_name}Deleted.{id}']ifid=="":groups=[f'{model_name}Created']returnasync_to_sync(root.detect_register_group_status)(groups,subscripe,requested_fields)Model Deleted SubscriptionsDefining a subscription that is fired whenever a given model instance is deleted can be accomplished like soimportgraphenefromgraphene_django.typesimportDjangoObjectTypefromCypartaGraphqlSubscriptionsTools.eventsimportDELETEDfromyour_app.modelsimportMyModelclassYourModelType(DjangoObjectType)classMeta:model=MyModelclassSubscription(graphene.ObjectType):my_model_deleted=graphene.Field(MyModelType,id=graphene.String(),subscripe=graphene.Boolean())# Resolve function for handling 'my_model_deleted' based on 'subscripe' and 'id'defresolve_my_model_deleted(root,info,subscripe,id):model_name=get_model_name_instance(MyModelType)returnasync_to_sync(root.detect_register_group_status)([f'{model_name}Deleted.{id}'],subscripe)Custom EventsTo create a custom type in GraphQL using Graphene, you need to define a new class for your custom type by extendinggraphene.ObjectType. Let's say you want to create a custom type namedCustomType. Here's an example:importgrapheneclassCustomType(graphene.ObjectType):# Define fields for your custom typefield1=graphene.String()field2=graphene.Int()# Add more fields as neededIn this example,CustomTypehas two fields:field1of typegraphene.String()andfield2of typegraphene.Int(). You can customize the fields based on the data you want to include in your custom type.Now, you can use thisCustomTypein yourmy_custom_eventsubscription:importgraphenemy_custom_event=graphene.Field(CustomType)defresolve_my_custom_event(root,info,subscripe):returnasync_to_sync(root.detect_register_group_status)(['custom_event'],subscripe)# elsewhere in your app:fromCypartaGraphqlSubscriptionsTools.eventsimporttrigger_subscriptionasync_to_sync(trigger_subscription)(f"{model_name}Created",self)