flaskdocker-composewebhooksdirectuseconnrefused

Recieving a directus webhook with a flask application (Connection Refused)


I have a directus instance running in a docker container.

The docker-compose.yml looks like this:


services:
  directus:
    image: directus/directus:9.22.1
    ports:
      - 8055:8055
    volumes:
      - ./database:/directus/database
      - ./extensions:/directus/extensions
      - ./uploads:/directus/uploads
    environment:
      KEY: "some-key"
      SECRET: "some-secret"

      DB_CLIENT: "sqlite3"
      DB_FILENAME: "/directus/database/data.db"

      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "d1r3ctu5"

      CORS_ENABLED: true

In the directus instance there is a webhook that gets triggered on new entries and sends the entry data to my flask app (or is supposed to do so). I use the url http://localhost:8080/webhook for this purpose.

The Flask app is supposed to listen on localhost:8080/webhook and print the data to the command line.

But when I trigger the webhook I recieve a "Connection refused" error message. I thought it was about the ports of the docker container, so I exposed 8080:8080 but that did not help.

The flask app:

import paho.mqtt.client as mqtt

from flask import Flask, request, Response

app = Flask(__name__)

app.run(host='localhost', port=8080)


@app.route('/webhook', methods=['POST'])
def return_response():
    print(request.json)
    message = "An new entry was created!"
    print(message)

the config for the webhook: The webhook

The Error message:

directus-directus-1  | [11:52:22.159] WARN: connect ECONNREFUSED 127.0.0.1:8080
directus-directus-1  |     err: {
directus-directus-1  |       "message": "connect ECONNREFUSED 127.0.0.1:8080: connect ECONNREFUSED 127.0.0.1:8080",
directus-directus-1  |       "name": "Error",
directus-directus-1  |       "stack":
directus-directus-1  |           Error: connect ECONNREFUSED 127.0.0.1:8080
directus-directus-1  |               at AxiosError.from (file:///directus/node_modules/axios/lib/core/AxiosError.js:89:14)
directus-directus-1  |               at RedirectableRequest.handleRequestError (file:///directus/node_modules/axios/lib/adapters/http.js:516:25)
directus-directus-1  |               at RedirectableRequest.emit (node:events:513:28)
directus-directus-1  |               at eventHandlers.<computed> (/directus/node_modules/follow-redirects/index.js:14:24)
directus-directus-1  |               at ClientRequest.emit (node:events:513:28)
directus-directus-1  |               at Socket.socketErrorListener (node:_http_client:494:9)
directus-directus-1  |               at Socket.emit (node:events:513:28)
directus-directus-1  |               at emitErrorNT (node:internal/streams/destroy:151:8)
directus-directus-1  |               at emitErrorCloseNT (node:internal/streams/destroy:116:3)
directus-directus-1  |               at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
directus-directus-1  |           caused by: Error: connect ECONNREFUSED 127.0.0.1:8080
directus-directus-1  |               at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1300:16)
directus-directus-1  |       "config": {
directus-directus-1  |         "transitional": {
directus-directus-1  |           "silentJSONParsing": true,
directus-directus-1  |           "forcedJSONParsing": true,
directus-directus-1  |           "clarifyTimeoutError": false
directus-directus-1  |         },
directus-directus-1  |         "transformRequest": [
directus-directus-1  |           null
directus-directus-1  |         ],
directus-directus-1  |         "transformResponse": [
directus-directus-1  |           null
directus-directus-1  |         ],
directus-directus-1  |         "timeout": 0,
directus-directus-1  |         "xsrfCookieName": "XSRF-TOKEN",
directus-directus-1  |         "xsrfHeaderName": "X-XSRF-TOKEN",
directus-directus-1  |         "maxContentLength": -1,
directus-directus-1  |         "maxBodyLength": -1,
directus-directus-1  |         "env": {},
directus-directus-1  |         "headers": {
directus-directus-1  |           "Accept": "application/json, text/plain, */*",
directus-directus-1  |           "Content-Type": "application/json",
directus-directus-1  |           "User-Agent": "axios/1.1.3",
directus-directus-1  |           "Content-Length": "324",
directus-directus-1  |           "Accept-Encoding": "gzip, deflate, br"
directus-directus-1  |         },
directus-directus-1  |         "url": "http://localhost:8080/webhook",
directus-directus-1  |         "method": "post",
directus-directus-1  |         "data": "{\"event\":\"items.create\",\"accountability\":{\"user\":\"d7c59a91-b6a8-4f1f-bcd6-95fc9d34c160\",\"role\":\"1ca3337b-aeed-4e5d-8076-06b949d59572\"},\"payload\":{\"publish_date\":\"2023-05-18T13:52:00+02:00\",\"title\":\"test\",\"author\":\"d7c59a91-b6a8-4f1f-bcd6-95fc9d34c160\",\"excerpt\":\"test\",\"body\":\"<p>test</p>\"},\"key\":19,\"collection\":\"articles\"}"
directus-directus-1  |       },

Solution

  • My problem was that I did not use the correct url while sending the webhook. Due to my directus instance running in a docker container, I only send the message to the localhost of the docker container. I fixed this by moving the flask app into the docker network.

    I created a new directory called app on the same level as the directus directory. Into the app directory I put a requirements.txt, the app script and a Dockerfile. The Dockerfile looks like this:

    # syntax=docker/dockerfile:1
    FROM python:3.10-alpine
    WORKDIR /code
    RUN apk add --no-cache gcc musl-dev linux-headers
    COPY requirements.txt requirements.txt
    RUN pip install -r requirements.txt
    COPY . .
    CMD ["python3", "app.py"]
    

    The Docker Compose file (which is placed in the parent directory of the directus and the app directory, looks like this:

    version: "3"
    
    services:
      directus:
        image: directus/directus:9.22.1
        ports:
          - "8055:8055"
        volumes:
          - ./directus/database:/directus/database
          - ./directus/extensions:/directus/extensions
          - ./directus/uploads:/directus/uploads
        environment:
          KEY: "some-key"
          SECRET: "some-secret"
    
          DB_CLIENT: "sqlite3"
          DB_FILENAME: "/directus/database/data.db"
    
          ADMIN_EMAIL: "admin@example.com"
          ADMIN_PASSWORD: "d1r3ctu5"
    
          CORS_ENABLED: true
    
    
    
      app:
        build: ./app
        ports:
            - "8080:8080"
    

    Now I can address each container using the name of the container. So I changed the webhook to

    http://app:8080/webhook
    

    I also changed the position and argument of the flask.run() call.

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/webhook', methods=['POST'])
    def webhook():
        return "Works", 200
    
    
    app.run(host='app', port=8080, debug=True) # called last, using the new host name.