Qual è il `content-type` corretto per modificare i post?

Ehi ragazzi, posso usare application/json come Content-Type quando aggiorno un post tramite l’API? La documentazione dice di sì, ma sto iniziando a pensare di non poterlo fare qui..

Ricevo costantemente [\"BAD CSRF\"] e non ho idea di cosa significhi.


Se devo usare multipart/form-data, avete qualche consiglio su come costruire la mia richiesta PUT? In particolare per i data.

header = CaseInsensitiveDict()
header["Authorization"] = '{"api-key": "longapikey", "api-username": "myusername"}'
{
  "post": {
      "raw": "Post interessante, ma ecco un aggiornamento al corpo del post",
      "edit_reason": "L'ho modificato perché posso."
   }
}

resp = requests.put(url, headers=headers, data=data)

Grazie!

Devi inviare Api-Key e Api-Username come intestazioni separate, non nell’intestazione Authorization. Una soluzione simile a questa dovrebbe funzionare meglio:

header = CaseInsensitiveDict()
header["Api-Key"] = 'longapikey'
header["Api-Username"] = 'myusername'

Sembra lo stesso problema del tuo argomento precedente:

2 Mi Piace

Grazie per la risposta, David.

È davvero strano: quando formattiamo l’intestazione come hai mostrato tu, ottengo:

{"errors":["Non sei autorizzato a visualizzare la risorsa richiesta. Il nome utente o la chiave API non sono validi."],"error_type":"invalid_access"}

Se aggiungo ["Authorization"], funziona.

Questo è per una semplice richiesta GET; non riesco ancora a fare il PUT.

Mi aspetterei che un’intestazione che funziona per un’operazione funzioni per tutte (purché la chiave sia globale - ed è proprio così). Quindi, al momento, non sono troppo preoccupato per l’intestazione… o dovrei esserlo?

Grazie!

Se la richiesta GET funziona anche quando la esegui in modo errato con l’intestazione Authorization, è probabile che ci sia qualcosa di malformato nella tua richiesta PUT. Funziona perché non è necessaria alcuna autorizzazione per effettuare la richiesta GET. Non esaminiamo nemmeno l’intestazione Authorization se la invii. Le richieste GET agli endpoint pubblici funzionano correttamente senza alcuna intestazione.

1 Mi Piace

@pedroleaoc ecco un piccolo esempio di script Python che dimostra come effettuare richieste autenticate e come inviare i dati della richiesta per le richieste PUT/POST.

# discourse-api-demo.py
import requests
from requests.structures import CaseInsensitiveDict

# Richiesta GET di base a un URL pubblico, nessuna intestazione necessaria.
url = "http://localhost:3000/posts/10.json"

resp = requests.get(url)

print(resp.status_code)
print(resp.content)

# Richiesta GET a un endpoint privato. Sono necessarie intestazioni di autenticazione.
url = "http://localhost:3000/admin/users/list/active.json"
headers = {'Api-Username': 'system', 'Api-Key': '5c1c57915e2...'}
resp = requests.get(url, headers=headers)

print(resp.status_code)
print(resp.content)

# Richiesta PUT con un corpo della richiesta
url = "http://localhost:3000/posts/10.json"
data = { 'raw': "Bellissimo post, ma ecco un aggiornamento al corpo del post", 'edit_reason': "Ho modificato questo perché potevo." }

resp = requests.put(url, headers=headers, json=data)
print(resp.status_code)
print(resp.content)

Da Quickstart — Requests 2.33.1 documentation

Invece di codificare il dict da soli, puoi anche passarlo direttamente utilizzando il parametro json (aggiunto nella versione 2.4.2) e verrà codificato automaticamente:

url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, json=payload)

Nota: il parametro json viene ignorato se viene passato data o files.

Utilizzare il parametro json nella richiesta cambierà il Content-Type nell’intestazione in application/json.

1 Mi Piace

Doh, certo! Non tutte le richieste GET richiedono l’autorizzazione!
È un ottimo suggerimento, ci darò un’occhiata. Grazie!

Cose che già so tramite reverse engineering:

  • api-key invece di api_key
  • La richiesta PUT richiede "content-type": "application/x-www-form-urlencoded"
  • I dati non sono in JSON (sono codificati, anche se non riesco a trovare la codifica corretta)

Vedi il mio post appena sopra questo. Puoi usare il formato json=data invece di data=data nella tua richiesta e la libreria Python requests si occuperà automaticamente dell’impostazione del content-type su application/json, che è quello che dovresti utilizzare.

2 Mi Piace

Fantastico, ora riesco a modificare il mio post! Grazie per il tuo aiuto!

C’è solo un ultimo problema: la chiave che sto usando è global. Quando provo con una chiave che ha solo le autorizzazioni write e read, ricevo il messaggio: Non sei autorizzato a visualizzare la risorsa richiesta. Il nome utente o la chiave API non sono validi.. Quando modifico il post tramite l’interfaccia grafica, sembra che venga effettuata una richiesta PUT all’URL del topic (oltre a quella che modifica effettivamente il post posts/post_id.json), che non riesco a riprodurre con una chiave API limitata, ma solo con quella globale. Non capisco però perché non dovrei essere in grado di modificare il post tramite l’API anche senza questa richiesta PUT aggiuntiva che avviene nell’interfaccia grafica.

MODIFICA: Tecnicamente, la mia chiave API copre /t/:slug/:topic_id, che è proprio l’endpoint a cui punta la richiesta PUT.

Hai selezionato l’ambito “edit Posts” per la tua chiave API?

No! Nemmeno ho quell’opzione! Controllerò, grazie ancora per l’aiuto.

1 Mi Piace

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.