что curl делает иначе, чем httr::POST, что вызывает 400 неверных запросов?

Я пытаюсь запросить данные из веб-API Materials Project в R.

В документации приведен пример запроса, который выполняется с использованием как curl, так и python. Я скопировал команду curl ниже.

curl -s --header "X-API-KEY: <YOUR-API-KEY>" \
    https://materialsproject.org/rest/v2/query \
    -F criteria='{"elements": {"$in": ["Li", "Na", "K"], "$all": ["O"]}, "nelements": 2}' \
    -F properties='["formula", "formation_energy_per_atom"]'

Из краткого руководства httr следует, что мне я должен быть в состоянии воспроизвести этот запрос с:

library(httr)
POST(url = "https://www.materialsproject.org/rest/v2/query",
     config = add_headers("X-API-KEY" = "<YOUR-API-KEY>",     
     body = list(criteria = "{'elements': {'$in': ['Li', 'Na', 'K'], '$all': ['O']}, 'nelements': 2}",
                 properties = "['formula', 'formation_energy_per_atom']"),
     encode = "multipart",
     verbose())

Но в то время как команда curl возвращает данные JSON из базы данных Materials Project, мой запрос R возвращает HTTP/1.1 400 BAD REQUEST. Что curl делает иначе, чем httr в приведенных выше кодах?

Я попытался поместить -v в curl и сравнить его с выводом (verbose()) выше, но curl не показывает, что он помещает в составную форму.

> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------d2ef2f3982185118
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Date: Tue, 27 Dec 2016 21:18:58 GMT
< Server: Apache/2.2.15 (CentOS)
< Vary: Accept-Encoding,User-Agent
< Connection: close
< Transfer-Encoding: chunked
< Content-Type: application/json

Тем временем httr показывает:

-> Content-Type: multipart/form-data; boundary=----------------------------5b4873dbc9cd
-> 
<- HTTP/1.1 100 Continue
>> ------------------------------5b4873dbc9cd
>> Content-Disposition: form-data; name="criteria"
>> 
>> {'elements': {'$in': ['Li', 'Na', 'K'], '$all': ['O']}, 'nelements': 2}
>> ------------------------------5b4873dbc9cd
>> Content-Disposition: form-data; name="properties"
>> 
>> ['formula', 'formation_energy_per_atom']
>> ------------------------------5b4873dbc9cd--

person wdkrnls    schedule 27.12.2016    source источник


Ответы (1)


Это действительно ужасный, плохо продуманный и лениво реализованный API. Кажется, им нравится Python, поэтому неудивительно, что это так.

Следующие работы:

library(httr)
library(jsonlite)

list(
  criteria=toJSON(list(
    elements=list(
      `$in`=c("Li", "Na", "K"),
      `$all`=c("0")
    ),
    nelements=unbox(2)
  )),
  properties=toJSON(c("formula", "formation_energy_per_atom"))
) -> params

POST(url="https://www.materialsproject.org/rest/v2/query",
     add_headers(`X-API-KEY`=Sys.getenv("MATERIALS_PROJECT_API_KEY")),
     body=params,
     encode="multipart", verbose()) -> res

и вот вывод verbose(), чтобы доказать это:

-> POST /rest/v2/query HTTP/1.1
-> Host: www.materialsproject.org
-> User-Agent: libcurl/7.51.0 r-curl/2.3 httr/1.2.1
-> Accept-Encoding: gzip, deflate
-> Accept: application/json, text/xml, application/xml, */*
-> X-API-KEY: wouldntyouliketoknow
-> Content-Length: 344
-> Expect: 100-continue
-> Content-Type: multipart/form-data; boundary=------------------------34f08173ce0a7818
-> 
<- HTTP/1.1 100 Continue
>> --------------------------34f08173ce0a7818
>> Content-Disposition: form-data; name="criteria"
>> 
>> {"elements":{"$in":["Li","Na","K"],"$all":["0"]},"nelements":2}
>> --------------------------34f08173ce0a7818
>> Content-Disposition: form-data; name="properties"
>> 
>> ["formula","formation_energy_per_atom"]
>> --------------------------34f08173ce0a7818--

<- HTTP/1.1 200 OK
<- Date: Wed, 28 Dec 2016 02:08:08 GMT
<- Server: Apache/2.2.15 (CentOS)
<- Vary: Accept-Encoding,User-Agent
<- Content-Encoding: gzip
<- Content-Length: 258
<- Connection: close
<- Content-Type: application/json
<- 

Он очень требователен к структуре строки запроса. Они действительно должны были просто принять тело JSON и покончить с этим. Но наполовину УДАЛЕНО - это путь народа питонов.

О боже, я только что заметил, что это сервер CentOS, предоставляющий ответы. Ага. Эти люди действительно любят боль.

person hrbrmstr    schedule 28.12.2016