Hello everybody!
When trying to post or update a message whose content exceeds a certain size (the exact size I cannot detemine yet - is there a way to check this?) NGINX refuses to accept the POST or PUT requests and returns Error 414.
Is there a way to change (permanently) the default configuration delivered with the Discourse image, so that a larger payload size (at least matching the default 32000 characters in the admin settings) is accepted via API?
Have you checked the settings for “max post size”? There is also discussion here about increasing it.
If your posts via the API are getting cut off smaller than that, I’d be surprised.
Yep, I did. It’s currently set to the default value of 32000 characters and I’m trying to push via API a payload of about 6000 characters. I think that the error comes from NGINX and not from Discourse…
After a bit of searching online I found that the problem might be related to the size of URL of the PUT request performed when I update a post via API.
This is actually rendering ineffective the setting “max post length” in Discourse admin, currently at the default value of 32000 characters.
Would it be possible to change the nginx template matching the web server configuration with the default Discourse configuration?
You can change nginx settings in the yml file. You can look in the discourse_docker/templates directory for some examples.
I usually edit them in the container to debug and then apply those settings to new containers in app.yml.
Just to document what I did for future visitors, I have manually added the options suggested in the topics linked in my previous message.
client_header_buffer_size 64k;
large_client_header_buffers 4 64k;
The values might be different for other users, but they look more than enough for my needs.
These options shall be manually added to the /etc/nginx/conf.d/discourse.conf NGINX configuration file, and after having restarted nginx service in the container, the problem will be solved.
Obviously this has to be redone manually at every container rebuild, unless this setting is added to the official web templates.
One last post - the error was caused by me, hence no change to the templates is needed, at all! 
I’m placing my API requests using the requests python library, and I was submitting the payload using parameter params=payload rather than data=payload, hence my oversized payload was handled in the “wrong” way.
I changed my call from this
r = requests.put(apiWebsite + '/posts/' + str(apiPost), params=payload)
to this
r = requests.put(apiWebsite + '/posts/' + str(apiPost), data=payload)
Sorry! 
[quote=“marcozambi, post:7, topic:98186, full:false”][/quote]
Estamos teniendo un problema similar al crear una publicación mediante el método POST.
Y cuando la publicación es larga, aparece el error 414.
Estamos utilizando la API de Discourse en Python para generar algunas publicaciones.
La función create_post parece realizar una solicitud POST usando parámetros (params) en lugar de datos (data).
Esta es la definición de create_post de la API de Discourse:
def create_topic(self, title, raw, category=None, created_at=None):
response = self._request('POST', 'posts.json', params={
'title': title,
'raw': raw,
'category': category,
'created_at': created_at,
})
Hemos intentado cambiar params por data en la definición de la función.
Hemos intentado usar PUT en lugar de POST.
Pero no funciona.
El problema parece ser que la publicación completa se pasa como parámetros en la URL en lugar de en un payload interno.
¿Es esto un error?
¿Cómo podemos crear una publicación larga usando un payload de datos en lugar de parámetros en la URL?
Hmm, no me queda muy claro qué tipo de módulo estás utilizando para enviar tu solicitud POST. Yo uso la librería requests y preparo una solicitud POST de la siguiente manera:
El método POST sirve para crear nuevos posts; PUT, para modificar los existentes.
Consulta la documentación de la API aquí: https://docs.discourse.org/
import requests, json
headers = {
'Content-Type': 'application/json',
'Api-key': envDiscourseKey, # Clave de API pasada en esta variable
'Api-username': envDiscourseUsername # Usuario de la API pasado en esta variable
}
tags = ['first-tag','second-tag']
payload = {
'title': 'Título de ejemplo',
'category': 123,
'tags': tags,
'raw': 'Texto sin procesar de tu post'
}
r = requests.post('https://www.yourwebsite.xyz/posts', headers=headers, data=json.dumps(payload))
returnedData = r.json()
status = r.status_code
Además, como explicé aquí, pasar el payload a través del parámetro params fue un error de mi parte y no debe hacerse.
Espero que esto te ayude.
Muchas gracias por su rápida respuesta.
Estamos utilizando un wrapper de Python para la API oficial de JavaScript de Discourse:
Parece ser un wrapper de la oficial de Discourse.
El problema es que en las definiciones utiliza params= (como pueden ver en la definición de la función extraída del archivo clients.py).
Pasa el título y los datos crudos en params.
Hemos cambiado la definición de la función create_post a data=, pero entonces no funciona.
Entiendo. Bueno, parece que el problema radica en la implementación del envoltorio.
En mi opinión, no necesitas ningún envoltorio. Aparte de los módulos requests y json, el código que publiqué es simplemente Python 3 puro.
Prueba a seguir ese enfoque, quizás definiendo tus propias funciones de envoltorio.
Vale, tienes razón.
El problema es que no somos muy proficientes en Python.
Pero parece que la implementación del wrapper no es buena.
Sin embargo, incluso si hemos cambiado los parámetros a datos en la definición de la función, no funciona.
Intentaremos usar este código para crear la publicación en lugar del código del envoltorio.
No soy quien está desarrollando el programa; programo en JavaScript y otros lenguajes, pero no en Python.
Intentaré explicarle al programador cómo hacerlo (está un poco confundido: estaba usando el envoltorio pensando que era la implementación oficial de la API de Discourse. El envoltorio usa ‘post’ como nombre del método para crear la publicación, mientras que la biblioteca subyacente de Python llama ‘post’ al método para enviar un mensaje POST. Creo que eso es lo que no está entendiendo bien).
Hemos probado su código, pero recibimos un error 403 como respuesta.
Parece que hay algún tipo de problema de autorización.
Pero estamos utilizando la misma clave de API y el mismo usuario que usamos anteriormente (con el envoltorio de API) y funcionaba…
¿Tiene alguna idea?
Le diré al programador que revise y lo explique mejor.
Están intentando usar Python, no curl.
El ejemplo que mencionan arriba tiene las cabeceras correctas.
Hola Marco,
Soy colega de Fernando. He implementado tu código y funciona perfectamente; el problema está resuelto.
¡Muchas gracias!
Albert.
Gracias a todos, especialmente a Marco, quien proporcionó el código en Python.
Ahora funciona.
Cometimos un error y usamos api-key en lugar de Api-key.
Lo corregimos y el código funciona.
No sé qué estaba mal en el wrapper que estábamos usando (además de usar params= en lugar de url).
Cambié params por data y no funcionó, pero el código parece hacer exactamente lo que dice Marco (aunque usando params, que no es la forma correcta).
Gracias de nuevo.
En nuestro lado no distingue entre mayúsculas y minúsculas, ¿verdad @blake?
No soy programador, no sé Python, solo le ayudé a solucionar el error.
¿Quizás Python distingue entre mayúsculas y minúsculas o hay una opción para activarlo?
El programa funcionó simplemente cambiando eso.
No. Rails/Rack convierte todos los encabezados a MAYÚSCULAS por nosotros. No hay nada en nuestro código que verifique la sensibilidad a mayúsculas y minúsculas.