How to make a JSON POST request from Java client to Python FastAPI server?

Question:

I send a post request from a java springboot application like this:

String requestBody = gson.toJson(sbert);
        System.out.println(requestBody); // If I print this, and use this in postman it works!
        HttpRequest add_request = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:4557/sbert_similarity"))
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .header("Content-Type", "application/json")
                .build();
        HttpResponse<String> response = client.sendAsync(add_request,
                HttpResponse.BodyHandlers.ofString()).get();

This is essentially what my fastapi service looks like:

from fastapi import FastAPI, Request
from pydantic import BaseModel
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer('all-MiniLM-L6-v2')
import pprint as pp
import uvicorn
from typing import Any

app = FastAPI()
class Item(BaseModel):
    user_input: str
    document: str
    
class ResponseItem(BaseModel):
    similarity: float

@app.post("/sbert_similarity")
def check_similarity(item: Item) -> ResponseItem:
    pp.pprint(item)
    sentences1 = [item.user_input]
    sentences2 = [item.document]
    cosine_score = 0
    embeddings1 = model.encode(sentences1, convert_to_tensor=True)
    embeddings2 = model.encode(sentences2, convert_to_tensor=True)
    cosine_score = util.cos_sim(embeddings1, embeddings2)
    
    return {
        "similarity" : cosine_score
    }

if __name__=="__main__":
    uvicorn.run("similarity_server:app",host='0.0.0.0', port=4557, reload=True, workers=3)

When I print out the returned json object I get:

{"detail":[{"loc":["body"],"msg":"field required","type":"value_error.missing"}]}

Which doesn’t make sense considering the same json object I use for the post request works perfectly fine when I use it in postman.

My fastapi server says: INFO: 127.0.0.1:65066 - "POST /sbert_similarity HTTP/1.1" 422 Unprocessable Entity

Anyone know what’s going on?

Thanks!

Edit:

So just a quick update it seems like from this code:

@app.post("/sbert_similarity_v3")
async def check_similarity(request: Request) -> Any:
    content_type = request.headers.get('Content-Type')
    
    if content_type is None:
        return 'No Content-Type provided.'
    elif content_type == 'application/json':
        try:
            json = await request.json()
            return json
        except JSONDecodeError:
            return 'Invalid JSON data.'
    else:
        return 'Content-Type not supported.'

there was a JSONDecodeError for all post requests sent from the Java Springboot application, I still don’t know why that is though?

Second Edit:

So, now I have to ask why is the http client sending a null object as opposed to it’s actual json object?

Asked By: Steveit

||

Answers:

The example below deomonstrates how to make a JSON POST request using HttpURLConnection. The issue in your code might or might not be with Apache’s HttpClient (you would need to test this on your own), but might be originated from the requestBody you send to the server; hence, I would suggest you manually specify a JSON string first (before using other Java serialization libraries, such as gson, to convert Java Objects into JSON), as shown below, and see how that works.

Working Example

Python FastAPI server (taken from this answer)

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class User(BaseModel):
    user: str


@app.post('/')
def main(user: User):
    return user

Java Client example

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;


public class PostJSON {

    public static void main(String[] args) throws IOException {
        URL url = new URL("http://127.0.0.1:8000/");
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("POST");
        con.setRequestProperty("Content-Type", "application/json");
        con.setRequestProperty("Accept", "application/json");
        con.setDoOutput(true);
        String jsonInputString = "{"user": "foo"}";

        try (OutputStream os = con.getOutputStream()) {
            byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
            os.write(input, 0, input.length);
        }

        try (BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) {
            StringBuilder response = new StringBuilder();
            String responseLine = null;
            while ((responseLine = br.readLine()) != null) {
                response.append(responseLine.trim());
            }
            System.out.println(con.getResponseCode() + " " + response);
        }
    }

}
Answered By: Chris
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.