Connecting to Microsoft Graph API Jython Code Fails

Good morning,

I have a Microsoft developer E5 account and a custom environment to test this problem in.

I followed the steps in this video:

I am using Ignition v8.1.35.

I am using the following python libraries which I already know don't all officially translate to Jython.

  • msal - 1.17.0
  • urllib3 - 2.1.0
  • request - 2.7.0

This is the code I am testing in the script console:

import json

import requests
from msal import ConfidentialClientApplication

client_id = {client_id}"
client_secret = "{client_secret}"
tenant_id = "{tenant_id}"

msal_authority = "https://login.microsoftonline.com/" + tenant_id

msal_scope = ["https://graph.microsoft.com/.default"]

msal_app = ConfidentialClientApplication(
	client_id = client_id,
	client_credential = client_secret,
	authority = msal_authority,
	
)

result = msal_app.acquire_token_silent(
	scopes = msal_scope,
	account = None,
)

if not result:
	result = msal_app.acquire_token_for_client(scopes = msal_scope)
	
access_token = result["access_token"]

print access_token


#api_result = requests.get(
#        msal_authority,
#        headers={'Authorization': 'Bearer ' + access_token},
#        timeout=30,
#    )
#
#print api_result

This code gives me an access token.

However, when I go on to uncomment out the last section (use the access_token) I get the response:

<Response [404]>

Does anyone know what else I can try here to display some results?

At the end of that video they connect to a different URL than you - why the change?

Oh yes, I forgot I changed stuff up while trying to get any response.

This is the updated code now...

import json

import requests
from msal import ConfidentialClientApplication

client_id ="{client_id}"
client_secret = "{client_secret}"
tenant_id = "{tenant_id}"

msal_authority = "https://login.microsoftonline.com/" + tenant_id

msal_scope = ["https://graph.microsoft.com/.default"]

msal_app = ConfidentialClientApplication(
	client_id = client_id,
	client_credential = client_secret,
	authority = msal_authority,
	
)

result = msal_app.acquire_token_silent(
	scopes = msal_scope,
	account = None,
)

if not result:
	result = msal_app.acquire_token_for_client(scopes = msal_scope)
	
access_token = result["access_token"]

print access_token


#api_result = requests.get(
#        msal_authority,
#        headers={'Authorization': 'Bearer ' + access_token},
#        timeout=30,
#    )
#

headers = {
	"Authorization":"Bearer " + access_token,
	"Content-Type": "application/json",
}

response = requests.get(
	url="https://graph.microsoft.com/v1.0/users",
	headers=headers,
)

print response

# Copy access_token and specify the MS Graph API endpoint you want to call, e.g. 'https://graph.microsoft.com/v1.0/groups' to get all groups in your organization
##access_token = '{ACCESS TOKEN YOU ACQUIRED PREVIOUSLY}'
#url = 'https://graph.microsoft.com/v1.0/groups'
#headers = {
#  'Authorization': access_token
#}
#
## Make a GET request to the provided url, passing the access token in a header
#graph_result = requests.get(url=url, headers=headers)
#
## Print the results in a JSON format
#print(graph_result.json())

And this is the error I get with the example:

Java Traceback:
Traceback (most recent call last):
  File "<input>", line 46, in <module>
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\api.py", line 69, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\api.py", line 50, in request
    response = session.request(method=method, url=url, **kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\sessions.py", line 465, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\sessions.py", line 605, in send
    r.content
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 750, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 750, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 303, in stream
    for line in self.read_chunked(amt, decode_content=decode_content):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 451, in read_chunked
    yield self._decode(chunk, decode_content=decode_content,
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 192, in _decode
    data = self._decoder.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 192, in _decode
    data = self._decoder.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 58, in decompress
    return self._obj.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 228, in decompress
    inflated = _get_inflate_data(self.inflater, max_length)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 291, in _get_inflate_data
    l = inflater.inflate(buf)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 291, in _get_inflate_data
    l = inflater.inflate(buf)
	at java.base/java.util.zip.Inflater.ensureOpen(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

java.lang.NullPointerException: java.lang.NullPointerException: Inflater has been closed


	at org.python.core.Py.JavaError(Py.java:545)

	at org.python.core.Py.JavaError(Py.java:536)

	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)

	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:208)

	at org.python.core.PyObject.__call__(PyObject.java:477)

	at org.python.core.PyObject.__call__(PyObject.java:481)

	at org.python.core.PyMethod.__call__(PyMethod.java:141)

	at zlib$py._get_inflate_data$15(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/zlib.py:303)

	at zlib$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/zlib.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:150)

	at org.python.core.PyFunction.__call__(PyFunction.java:426)

	at zlib$py.decompress$11(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/zlib.py:247)

	at zlib$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/zlib.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:141)

	at org.python.core.PyFunction.__call__(PyFunction.java:426)

	at org.python.core.PyMethod.__call__(PyMethod.java:141)

	at requests.packages.urllib3.response$py.decompress$8(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py:58)

	at requests.packages.urllib3.response$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:150)

	at org.python.core.PyFunction.__call__(PyFunction.java:426)

	at org.python.core.PyMethod.__call__(PyMethod.java:141)

	at requests.packages.urllib3.response$py._decode$18(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py:203)

	at requests.packages.urllib3.response$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:197)

	at org.python.core.PyFunction.__call__(PyFunction.java:485)

	at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:237)

	at org.python.core.PyMethod.__call__(PyMethod.java:228)

	at requests.packages.urllib3.response$py.read_chunked$32(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py:466)

	at requests.packages.urllib3.response$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyGenerator.__iternext__(PyGenerator.java:161)

	at org.python.core.PyGenerator.__iternext__(PyGenerator.java:143)

	at requests.packages.urllib3.response$py.stream$20(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py:306)

	at requests.packages.urllib3.response$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/packages/urllib3/response.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyGenerator.__iternext__(PyGenerator.java:161)

	at org.python.core.PyGenerator.__iternext__(PyGenerator.java:143)

	at requests.models$py.generate$41(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/models.py:689)

	at requests.models$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/models.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyGenerator.__iternext__(PyGenerator.java:161)

	at org.python.core.PyGenerator.__iternext__(PyGenerator.java:143)

	at org.python.core.PySequence.fastSequence(PySequence.java:314)

	at org.python.core.PyString.str_join(PyString.java:3271)

	at org.python.core.PyString$str_join_exposer.__call__(Unknown Source)

	at org.python.core.PyObject.__call__(PyObject.java:465)

	at requests.models$py.content$43(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/models.py:758)

	at requests.models$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/models.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:134)

	at org.python.core.PyFunction.__call__(PyFunction.java:416)

	at org.python.core.PyFunction.__call__(PyFunction.java:411)

	at org.python.core.PyProperty.property___get__(PyProperty.java:82)

	at org.python.core.PyProperty.__get__(PyProperty.java:71)

	at org.python.core.PyObject.object___findattr__(PyObject.java:3766)

	at org.python.core.Deriveds.__findattr_ex__(Deriveds.java:43)

	at org.python.core.PyObjectDerived.__findattr_ex__(PyObjectDerived.java:1036)

	at org.python.core.PyObject.__getattr__(PyObject.java:957)

	at requests.sessions$py.send$21(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/sessions.py:607)

	at requests.sessions$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/sessions.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:197)

	at org.python.core.PyFunction.__call__(PyFunction.java:485)

	at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:237)

	at org.python.core.PyMethod.__call__(PyMethod.java:228)

	at org.python.core.PyMethod.__call__(PyMethod.java:223)

	at org.python.core.PyObject._callextra(PyObject.java:589)

	at requests.sessions$py.request$13(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/sessions.py:467)

	at requests.sessions$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/sessions.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:197)

	at org.python.core.PyFunction.__call__(PyFunction.java:485)

	at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:237)

	at org.python.core.PyMethod.__call__(PyMethod.java:228)

	at org.python.core.PyMethod.__call__(PyMethod.java:223)

	at org.python.core.PyObject._callextra(PyObject.java:589)

	at requests.api$py.request$1(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/api.py:55)

	at requests.api$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/api.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyFunction.function___call__(PyFunction.java:474)

	at org.python.core.PyFunction.__call__(PyFunction.java:469)

	at org.python.core.PyFunction.__call__(PyFunction.java:464)

	at org.python.core.PyObject._callextra(PyObject.java:589)

	at requests.api$py.get$2(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/api.py:69)

	at requests.api$py.call_function(C:/Users/bmeyers/.ignition/cache/gwlocalhost_8088/C0/pylib/requests/api.py)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)

	at org.python.core.PyFunction.function___call__(PyFunction.java:474)

	at org.python.core.PyFunction.__call__(PyFunction.java:469)

	at org.python.pycode._pyx17.f$0(<input>:51)

	at org.python.pycode._pyx17.call_function(<input>)

	at org.python.core.PyTableCode.call(PyTableCode.java:173)

	at org.python.core.PyCode.call(PyCode.java:18)

	at org.python.core.Py.runCode(Py.java:1703)

	at org.python.core.Py.exec(Py.java:1747)

	at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:277)

	at org.python.util.InteractiveInterpreter.runcode(InteractiveInterpreter.java:130)

	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:628)

	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:616)

	at java.desktop/javax.swing.SwingWorker$1.call(Unknown Source)

	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)

	at java.desktop/javax.swing.SwingWorker.run(Unknown Source)

	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

	at java.base/java.lang.Thread.run(Unknown Source)

Caused by: java.lang.NullPointerException: Inflater has been closed

	at java.base/java.util.zip.Inflater.ensureOpen(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)

	... 111 more

Traceback (most recent call last):
  File "<input>", line 46, in <module>
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\api.py", line 69, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\api.py", line 50, in request
    response = session.request(method=method, url=url, **kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\sessions.py", line 465, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\sessions.py", line 605, in send
    r.content
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 750, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 750, in content
    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\models.py", line 673, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 303, in stream
    for line in self.read_chunked(amt, decode_content=decode_content):
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 451, in read_chunked
    yield self._decode(chunk, decode_content=decode_content,
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 192, in _decode
    data = self._decoder.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 192, in _decode
    data = self._decoder.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\requests\packages\urllib3\response.py", line 58, in decompress
    return self._obj.decompress(data)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 228, in decompress
    inflated = _get_inflate_data(self.inflater, max_length)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 291, in _get_inflate_data
    l = inflater.inflate(buf)
  File "C:\Users\bmeyers\.ignition\cache\gwlocalhost_8088\C0\pylib\zlib.py", line 291, in _get_inflate_data
    l = inflater.inflate(buf)
	at java.base/java.util.zip.Inflater.ensureOpen(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/java.util.zip.Inflater.inflate(Unknown Source)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.base/java.lang.reflect.Method.invoke(Unknown Source)

java.lang.NullPointerException: java.lang.NullPointerException: Inflater has been closed

It was mad about something with zlib.py and that is when I started looking into older versions of the libraries and then things just got worse so I posted here looking for any advice/input.

After updating to requests 2.11.1 I was able to get a valid response. Proceeding to try and interact with TEAMs...

1 Like

So after getting another step further I think I have hit a dead end in sending messages to Microsoft Teams one-on-one chats.

TL:DR - Not possible without delegated permissions.

import json

import requests
from msal import ConfidentialClientApplication

client_id = "{client_id}"
client_secret = "{client_secret}"
tenant_id = "{tenant_id}"

msal_authority = "https://login.microsoftonline.com/" + tenant_id

msal_scope = ["https://graph.microsoft.com/.default"]

msal_app = ConfidentialClientApplication(
	client_id = client_id,
	client_credential = client_secret,
	authority = msal_authority,
	
)

result = msal_app.acquire_token_silent(
	scopes = msal_scope,
	account = None,
)

if not result:
	result = msal_app.acquire_token_for_client(scopes = msal_scope)
	
access_token = result["access_token"]

print access_token

url = 'https://graph.microsoft.com/v1.0/teams/{teams_id}/channels/{channel_id}/messages'
headers = {
  'Authorization': access_token
}
data = {
    "body": {
        "content": "Hello world"
    }
}

graph_result = requests.post(url=url, json=data, headers=headers)

print(graph_result.json())

And the resulting error is:

{u'error': {u'code': u'Unauthorized', u'message': u'Message POST is allowed in application-only context only for import purposes. Refer to https://docs.microsoft.com/microsoftteams/platform/graph-api/import-messages/import-external-messages-to-teams for more details.', u'innerError': {u'date': u'2023-12-18T14:59:24', u'request-id': u'{request_id}', u'client-request-id': u'{client_request_id}'}}}

Which means I don't have delegated permissions from Ignition. I am a bit stuck here but looks like my potential options are:

  1. Use a webhook to send messages to a channel, create a bot to distribute the messages to individual users.
  1. Use a webhook to create necessary channels, register the channels with Ignition, and POST messages accordingly to the channel (users can "subscribe" to whatever channel they need then.

What are you ultimately trying to achieve?

I wanted Ignition to send one-on-one chats to Microsoft TEAMs users to alert them that a specific workstation on the floor was requesting help [using the webdev module].

3 Likes

That sounds pretty cool, actually. Please continue blazing a trail for the rest of us. :grin:

7 Likes

Hmm, based on a quick scan of those docs it sounds like you need to build a "bot".

I'm not sure the WebDev module is relevant here.

Can I call webhooks without the webdev module?

Making HTTP requests does not require WebDev.

Receiving inbound HTTP requests does.

2 Likes

Oh yes... I was confused. Too early in the week for thinking :smiley:

It appears that Microsoft Teams allows someone to make a bot that can handle various incoming POSTs and I'll post the full tutorial when I finish.

Curiously though I can't get system.net.httpClient to work as expected. I have gotten results using the requests library and the system.net.httpPost function. Any idea what my code for httpClient is missing?

#
# This code works
import requests

url = 'http://localhost:3978/api/notification'
headers = {'Content-Type' : 'application/json'}
data = {}

results = requests.post(url=url, json=data, headers=headers)

print results
# This code works.
url = 'http://localhost:3978/api/notification'

response = system.net.httpPost(url)

print response
# This code has not worked yet.
client = system.net.httpClient()

url = 'http://localhost:3978/api/notification'
#headers = {'Content-Type' : 'application/json'}
#data = {}

response = client.post(url=url)

print response

I mean... as you've provided it, you're not posting any data.

I mean that is technically true... however I am also not posting any data when using system.net.httpPost and that example works for me.

I don't know, use Wireshark to spy on the traffic to the localhost webserver and see what's different.

Sending an empty data dictionary in httpClient should automatically set the content type to application/json. Make sure you're passing it with keyword arguments?

Also, make sure you cache your httpClient instance--they are meant to be re-used, and will leak memory if you keep making more.

Using httpPost -

And using httpClient -

It appears that httpClient defaults to version HTTP_2 while httpPost is using HTTP_1_1. By setting the version in my httpClient call to HTTP_1_1 I was able to get a result.

# This code works with version specified HTTP_1_1.
client = system.net.httpClient(version='HTTP_1_1')

url = 'http://localhost:3978/api/notification'

response = client.post(url=url)

print response
3 Likes