Package: django-microservices-communication
Easy communication for django based microservicesLibrary provides tools for:Publisher/Subscription patternSending async commandREST APIInstallationpip install git+https://github.com/ksinn/django-microservices-communicationInrequirements.txtfile...Django==4.2git+https://github.com/ksinn/django-microservices-communicationdjango-cors-headers==3.14.0...Installation in DockerIf pip install execute in docker, you require git in image.Add 'services_communication' to your INSTALLED_APPS setting.INSTALLED_APPS=[...'services_communication',]Any global settings are kept in a single configuration dictionary named MICROSERVICES_COMMUNICATION_SETTINGS.
Start off by adding the following to your settings.py module:MICROSERVICES_COMMUNICATION_SETTINGS={'APP_ID':'my-service','BROKER_CONNECTION_URL':'amqp://guest:guest@localhost:5672',# or set as connection params dict'BROKER_CONNECTION_PARAMETERS':{'host':'localhost','port':5672,'virtual_host':None,'username':'guest','password':'guest',# Instead username and password you may set pika credentials object'credentials':pika.PlainCredentials('guest','guest')},'QUEUE':'my-queue','EXCHANGES':['my-exchange1',('my-other-exchange','fanout'),'exchange3',],'BINDS':[('my-exchange1','event.*'),'my-other-exchange',],'REST_API_HOST':'http://api.example.com','REST_API_AUTH_URL':'api/v1/login',# Set auth request body'REST_API_CREDENTIAL':{'login':'sarvar','password':'sarvar',},# Or username and password, if filed named as 'username' and 'password''REST_API_USERNAME':'myusername','REST_API_PASSWORD':'12345',}Defaults:exchange type -topicbind routing key -'#'Async communicationConsumingWrite logical consuming function in file 'consumers.py' in django appsome_project/
    | some_project/
        | settings.py
        | urls.py
    | some_app/
        | __init__.py
        | admin.py
        | apps.py
        | consumers.py  <---- 
        | models.py
        | tests.py
        | viwes.py
    | some_other_app/
        | __init__.py
        | admin.py
        | apps.py
        | consumers.py  <----
        | models.py
        | tests.py
        | viwes.pyConsumer function must be registered in message router.
Basic consumer function mast accept 2 positional arguments:routing keyandmessage body.Example  consumers.py file:from services_communication.consumer import message_router

@message_router.consumer('my-exchange1', 'event.update')
@message_router.consumer('my-exchange1', 'event.create')
@message_router.consumer('my-other-exchange')  # For get all routing keys
@message_router.consumer()  # For get all exchange (default consumer)
def stupid_consume_function(routing_key, body):
    print(routing_key, body)


@message_router.default_consumer  # For get message not routed to other consumers
def stupid_consume_function(routing_key, body):
    print(payload)If you want to consume aggregate event, use decorator@event_consumerand after then consumer function mast accept only on positional argumentevent payloadand other event data askwargsExample  consumers.py file:from services_communication.consumer import message_router

@message_router.consumer('my-exchange1', 'event.update')
@message_router.consumer('my-exchange1', 'event.create')
@message_router.consumer('my-ether_exchange')  # For get all routing keys
@event_consumer
def stupid_consume_function(payload, **kwargs):
    print(payload)Run consumerpython manage.py runconsumerOr userdevconsumerfor auto reloading on change filesPublishingPublishing in transactionFor publish event happened withaggregatein transaction use publish_aggregate_eventfromservices_communication.publisherimportpublish_aggregate_eventdefupdate_user_name(user,new_name):user.name=new_nameuser.save()publish_aggregate_event(aggregate='user',event_type='update.base',payload=build_user_data(user),)This function save event data in db table.
Then publisher process will read the event from the table and publish it to the broker inexchangesame as aggregate name withrouting keysame as event type,
event_type and body:{"eventId":"2","eventTime":"2023-06-02T10:58:58.340174Z","eventType":"update.base","aggregate":"user","payload":{...},}Run publisher processpython manage.py runpublisherOr userdevpublisherfor auto reloading on change filesCommandsA command is a way of telling remote service to do something without waiting for a response from it.For send command immediately, without regard to transactionality, usesend_commandwith service name and payloads as arguments.You can set timeout in seconds for command executing, this means that the executor of the command should not execute it if the specified time has passed since the time it was sent (calledsend_commandfunction).fromservices_communication.callimportsend_commandsend_command('sms',{'phone':'998990000000','text':'Hello world!',})If remote service has any commands, you may want to use optional argumentcommand_name.Sync communicationREST APIFor request endpoint use method functions from rest_api package.fromservices_communication.rest_apiimportget,post,head,deletefromservices_communication.rest_api.formatterimportfull_responsefirst_subject=get('api/v1/subjects/1')# return only response body as dictfirst_subject=get('api/v1/subjects',params={'page':2,'size':20,},)# sending query paramsresponse=get('api/v1/subjects/1',response_formatter=full_response)# return response objectnew_subject=post('api/v1/subjects',json={'name':'My new subject','order':5,},)# sending request bodyIn all methods function you can send additional keyword argument, it was sent to request.For formatting request and response uoy can send custom function asrequest_formatterandresponse_formatterkeyword arguments.request_formatterwill be applied to other request arguments(params, json, data).response_formatterwill be applied to response and it result be returned from method.By default:get, post, delete methods return response.jsonhead method return full response