JavaScript Mapping Library
So remember a long time ago (Tuesday), when I blogged about using the Bluesky API with BoxLang? As expected, I’m following that up today with a look at using the Mastodon APIs. Personally, I’m down to just two social networks, Bluesky and Mastodon. Originally I was using Mastodon a lot more, but I’ve been vibing with Bluesky more lately so I tend to check it more often. That being said, whenever I release a new blog post, I’ve got an automated process to post to both, so I thought I should cover both for BoxLang as well.
Even better… I already did this in ColdFusion! Way back in October 2023, I blogged about the topic and even shared a simple ColdFusion component for it. That made ‘translating’ to BoxLang even easier.
As a refresher, authentication with Mastodon is simpler. In your profile, you go into your developer settings and create a token. That’s it. All you need along with that is the server your account runs on. So I specified too environment variables for this, MASTO_TOKEN and MASTO_SERVER. I verified it like so:
MASTO_TOKEN = server.system.environment?.MASTO_TOKEN ?: ''; MASTO_SERVER = server.system.environment?.MASTO_SERVER ?: ''; if(MASTO_TOKEN == "" || MASTO_SERVER == "") { println('Ensure the Mastodon token env vars are set: MASTO_TOKEN and MASTO_SERVER'); abort; }
As I said, you don’t need anything more than that token, so posting a toot (message) is as simple as:
toot = 'Hello World from BoxLang, #now()#'; bx:http url='https://#MASTO_SERVER#/api/v1/statuses' method='post' result='result' { bx:httpparam type='header' name='Authorization' value='Bearer #MASTO_TOKEN#'; bx:httpparam type='formfield' name='status' value=toot; }
Literally, that’s it. You get a large post object back you can inspect if need be.
How about images? Like Bluesky, they’ve got a different endpoint for that. Here’s an example sending up a cat picture.
bx:http url='https://#MASTO_SERVER#/api/v2/media' method='post' result='result' { bx:httpparam type='header' name='Authorization' value='Bearer #MASTO_TOKEN#'; bx:httpparam type='file' name='file' file=expandPath('./cat1.jpg'); } mediaOb = result.filecontent.fromJSON();
This returns a media object where all you need is the id, and to add it to your post, it’s one line of code:
toot = 'Hello World from BoxLang, #now()#, with an image.'; bx:http url='https://#MASTO_SERVER#/api/v1/statuses' method='post' result='result' { bx:httpparam type='header' name='Authorization' value='Bearer #MASTO_TOKEN#'; bx:httpparam type='formfield' name='status' value=toot; bx:httpparam type='formfield' name='media_ids[]' value=mediaOb.id; }
Here’s a complete script showing this in action:
MASTO_TOKEN = server.system.environment?.MASTO_TOKEN ?: ''; MASTO_SERVER = server.system.environment?.MASTO_SERVER ?: ''; if(MASTO_TOKEN == "" || MASTO_SERVER == "") { println('Ensure the Mastodon token env vars are set: MASTO_TOKEN and MASTO_SERVER'); abort; } toot = 'Hello World from BoxLang, #now()#'; bx:http url='https://#MASTO_SERVER#/api/v1/statuses' method='post' result='result' { bx:httpparam type='header' name='Authorization' value='Bearer #MASTO_TOKEN#'; bx:httpparam type='formfield' name='status' value=toot; } dump(result.fileContent); // test with media bx:http url='https://#MASTO_SERVER#/api/v2/media' method='post' result='result' { bx:httpparam type='header' name='Authorization' value='Bearer #MASTO_TOKEN#'; bx:httpparam type='file' name='file' file=expandPath('./cat1.jpg'); } mediaOb = result.filecontent.fromJSON(); toot = 'Hello World from BoxLang, #now()#, with an image.'; bx:http url='https://#MASTO_SERVER#/api/v1/statuses' method='post' result='result' { bx:httpparam type='header' name='Authorization' value='Bearer #MASTO_TOKEN#'; bx:httpparam type='formfield' name='status' value=toot; bx:httpparam type='formfield' name='media_ids[]' value=mediaOb.id; } dump(result.fileContent.fromJSON());
I turned this into a BoxLang class. It’s a bit different from the Bluesky one in terms of API shape and I may address that at some point, but for now, here’s that class:
class { property name="token" type="string"; property name="server" type="string"; public function uploadMedia(required string path) { checkAuth(); bx:http url='https://#variables.server#/api/v2/media' method='post' result='result' { bx:httpparam type='header' name='Authorization' value='Bearer #variables.token#'; bx:httpparam type='file' name='file' file=path; } return result.fileContent.fromJSON(); } public function post(required string toot, image="") { checkAuth(); bx:http url='https://#variables.server#/api/v1/statuses' method='post' result='result' { bx:httpparam type='header' name='Authorization' value='Bearer #variables.token#'; bx:httpparam type='formfield' name='status' value=toot; if(image !== '') { imageOb = uploadMedia(image); bx:httpparam type='formfield' name='media_ids[]' value=imageOb.id; } } return result.fileContent.fromJSON(); } /* * Utility function to ensure auth is set. */ private function checkAuth() { if(variables.token == "" || variables.server == "") { throw("Component initialized with blank, or missing, handle and password values."); } } }
And an example using it:
masto = new mastodon(token=MASTO_TOKEN, server=MASTO_SERVER); post = masto.post("Hello from the API, promise this is the last(ish) test."); dump(post); // now with an image test post = masto.post("Honest, this should be the last test. Really.",expandPath('./cat1.jpg')); dump(post); println('done');
Here’s my most recent test on one of my cooler bot accounts:
Post by @dragonhoards@mastodon.social View on Mastodon
Fairly simple, right? If you take this along with the code from the previous post, you could easily automate posting to both in a few lines of code.
As before, you can find these samples in the BoxLang demos repo here: https://github.com/ortus-boxlang/bx-demos/tree/master/scripting Look for test_mastodon.bxs, test_mastodon2.bxs, and mastodon.bx. Enjoy!
test_mastodon.bxs
test_mastodon2.bxs
mastodon.bx
Raymond Camden
You must be logged in to post a comment.
This site uses Akismet to reduce spam. Learn how your comment data is processed.