Getting error 400 when doing a POST query in Java

Hi everybody.

I’m new here and I’m setting up a Java application that connects to the MAPI through a library called UniREST.
I’ve read the other topic “HTTP400 when making POST query via MATLAB
but still, I cannot figure out what to do.

Now I’m able to do all the GET queries correctly, but when it comes to the mp-query POST one, it doesn’t work.
I get the following error:

{
  "valid_response": false,
  "error": "'criteria'",
  "version": {
    "db": "2021_02_08",
    "pymatgen": "2021.2.8.1",
    "rest": "2.0"
  },
  "created_at": "2021-03-04T16:36:49.782378",
  "traceback": "Traceback (most recent call last):\n  File \"/opt/miniconda3/envs/mpprod3/lib/python3.6/site-packages/django/utils/datastructures.py\", line 78, in __getitem__\n    list_ = super().__getitem__(key)\nKeyError: 'criteria'\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n  File \"/var/www/python/matgen_prod/materials_django/rest/rest.py\", line 94, in wrapped\n    d = func(*args, **kwargs)\n  File \"/var/www/python/matgen_prod/materials_django/rest/rest.py\", line 205, in query\n    criteria = json.loads(post[\"criteria\"])\n  File \"/opt/miniconda3/envs/mpprod3/lib/python3.6/site-packages/django/utils/datastructures.py\", line 80, in __getitem__\n    raise MultiValueDictKeyError(key)\ndjango.utils.datastructures.MultiValueDictKeyError: 'criteria'\n"
}

Now I tried both posting a JSON object or a string but it doesn’t seem to work.
My stack trace looks like this:

RESTClient  - Putting https://www.materialsproject.org/rest/v2/query < {"criteria":{"elements":{"$in":["Li","Na","K"],"$all":["O"]},"nelements":2},"properties":["formula","formation_energy_per_atom"]} ...

782.headers - http-outgoing-0 >> POST /rest/v2/query HTTP/1.1
782.headers - http-outgoing-0 >> Accept: application/json
782.headers - http-outgoing-0 >> Content-Type: application/json
782.headers - http-outgoing-0 >> X-API-KEY: XXXXXXXXXXXXXXXXXXXXXXX
783.headers - http-outgoing-0 >> user-agent: unirest-java/3.1.00
783.headers - http-outgoing-0 >> accept-encoding: gzip
783.headers - http-outgoing-0 >> Content-Length: 129
783.headers - http-outgoing-0 >> Host: www.materialsproject.org
783.headers - http-outgoing-0 >> Connection: Keep-Alive

783.wire  - http-outgoing-0 >> "POST /rest/v2/query HTTP/1.1[\r][\n]"
783.wire  - http-outgoing-0 >> "Accept: application/json[\r][\n]"
783.wire  - http-outgoing-0 >> "Content-Type: application/json[\r][\n]"
783.wire  - http-outgoing-0 >> "X-API-KEY: gocOONKxUjB3oQkt[\r][\n]"
783.wire  - http-outgoing-0 >> "user-agent: unirest-java/3.1.00[\r][\n]"
783.wire  - http-outgoing-0 >> "accept-encoding: gzip[\r][\n]"
783.wire  - http-outgoing-0 >> "Content-Length: 129[\r][\n]"
783.wire  - http-outgoing-0 >> "Host: www.materialsproject.org[\r][\n]"
783.wire  - http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
783.wire  - http-outgoing-0 >> "[\r][\n]"
783.wire  - http-outgoing-0 >> "{"criteria":{"elements":{"$in":["Li","Na","K"],"$all":["O"]},"nelements":2},"properties":["formula","formation_energy_per_atom"]}"

1354.wire - http-outgoing-0 << "HTTP/1.1 400 Bad Request[\r][\n]"
1354.wire - http-outgoing-0 << "Date: Thu, 04 Mar 2021 16:36:49 GMT[\r][\n]"
1354.wire - http-outgoing-0 << "Content-Type: application/json[\r][\n]"
1354.wire - http-outgoing-0 << "Transfer-Encoding: chunked[\r][\n]"
1354.wire - http-outgoing-0 << "vary: Accept-Encoding,User-Agent[\r][\n]"
1354.wire - http-outgoing-0 << "strict-transport-security: max-age=31536000[\r][\n]"
1354.wire - http-outgoing-0 << "CF-Cache-Status: DYNAMIC[\r][\n]"
1354.wire - http-outgoing-0 << "cf-request-id: 089fb26e2f0000bf198dbe2000000001[\r][\n]"

1356.headers  - http-outgoing-0 << HTTP/1.1 400 Bad Request
1356.headers  - http-outgoing-0 << Date: Thu, 04 Mar 2021 16:36:49 GMT
1356.headers  - http-outgoing-0 << Content-Type: application/json
1356.headers  - http-outgoing-0 << Transfer-Encoding: chunked
1356.headers  - http-outgoing-0 << vary: Accept-Encoding,User-Agent
1356.headers  - http-outgoing-0 << strict-transport-security: max-age=31536000
1356.headers  - http-outgoing-0 << CF-Cache-Status: DYNAMIC
1356.headers  - http-outgoing-0 << cf-request-id: 089fb26e2f0000bf198dbe2000000001

1357.headers  - http-outgoing-0 << NEL: {"max_age":604800,"report_to":"cf-nel"}
1357.headers  - http-outgoing-0 << Server: cloudflare
1357.headers  - http-outgoing-0 << CF-RAY: 62ac86904843bf19-FRA
1357.headers  - http-outgoing-0 << alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400
1357.headers  - http-outgoing-0 << Connection: Keep-Alive
1357.headers  - http-outgoing-0 << Content-Encoding: gzip

1371 [main] ERROR RESTClient  - [postMpQuery] An error occurred: null will be returned [status: 400, message: Bad Request].

From what I’ve read I have to POST the mpquery as a String serialized from a JSON.
What am I doing wrong?

I’m not familiar with the specific REST client you’re using (btw, beware you’ve pasted your API key in plain text here), but this sort of query should be a POST to https://materialsproject.org/rest/v2/query with data being the JSON with criteria and properties. In other words, your example looks correct to me

I would perhaps try a simpler query just for testing, e.g. {'criteria': '{"task_id": "mp-13"}', 'properties': '["pretty_formula"]'} (this should return [{'pretty_formula': 'Fe'}]).

If you can read Python, we actively maintain a first-party Python client to access this API (MPRester in pymatgen which uses the popular requests library to make the requests. You could take a look at this to see where the error may be.

Note that we have a new API on the horizon with an OpenAPI spec which might be more helpful long term. The current API has served us well over the last 10 years but it’s not the most well thought-out API by current standards.