Unable to lock post with API

AI-generated summary

Unable to lock post with API

mksafi is experiencing issues with locking a post using the Discourse API. Despite making a correct PUT request to https://forum.hollowverse.com/posts/1817/locked.json with the required headers and locked: true in the request body, the API responds with {locked: false}.

mksafi has tried reverse-engineering the Discourse client’s API call and found it similar to their own implementation. However, RGJ discovered that the issue lies in the API’s expectation of a string comparison for the locked parameter. The solution is to send "locked": "true" instead of "locked": true. This is because the browser sends Content-Type: application/x-www-form-urlencoded, which interprets the parameter as a string, making it work in the browser but not in the API request.

mksafi has thanked RGJ for their help and plans to update the documentation with a pull request.

I make a couple of API calls from my application to Discourse to modify posts.

In the first call I edit the post. That works great. In the next call I try to lock the post.

My post locking call from JavaScript looks like this

fetch(`https://forum.hollowverse.com/posts/1817/locked.json`, {
  method: 'PUT',
  headers: {
    'Api-Key': process.env.DISCOURSE_SYSTEM_PRIVILEGE_SECRET,
    'content-type': 'application/json',
    'Api-Username': 'hollowbot',
  },
  body: JSON.stringify({locked: true}),
});

When I fire this call, Discourse responds to me with {locked: false}.

I tried locking the post manually and inspecting the API call that the Discourse client makes, and it looks very similar to the one I make from my application, with the exception of the authentication method, perhaps.

No sure what’s going on, any ideas?

I don’t see an obvious problem. Did you get that by following How to reverse engineer the Discourse API? That’s what I’d do to help if I were at my computer.

The API to lock a post is documented here Discourse API Docs but yeah, I also tried to reverse engineer how the Discourse client does it, and it looks very similar to the way I’m doing it from my application.

The code is

params[:locked] === "true" ? locker.lock : locker.unlock

Which seems to be doing a string compare.

That means that you would need to send "locked": "true" and not "locked": true and that the documentation or code would need to be updated to reflect or change this behavior.

The browser does not send a JSON request, it sends Content-Type: application/x-www-form-urlencoded which will interpret the parameter as a string, and that is why it does work in the browser.

Thank you for your help Richard!

TIL!

And I’ll look into PRing an update to the docs.