Joan Martín
Joan Martín

Reputation: 129

How can I send a post request with Retrofit?

I'm trying to send post request with Retrofit but server response an error 400: Bad Request.

BaseURL : http://taskdemoserver.pythonanywhere.com

This is a screenshot of server documentation.

Server doc

This is the Retrofit Interface.

package com.e.databaseapp

import retrofit2.Call
import retrofit2.http.*

interface Service {
    @Headers("user: joan","Content-Type: application/json")
    @GET( "task" )
    fun getListTask() : Call<TaskListContainer>

    @Headers("user: joan","Content-Type: application/json")
    @POST("task")
    fun saveTask (@Body task: Task) : Call<Task>

    @Headers("user: joan")
    @DELETE("task")
    fun deleteTask (task: String) : Call<Void>
}

I create an instance of Retrofit in my repository.

lass TaskRepository(val taskDao: TaskDao) {
    val gson : Gson = GsonBuilder()
        .setLenient()
        .create()

    val loggingInterceptor : HttpLoggingInterceptor = HttpLoggingInterceptor()
        .setLevel(HttpLoggingInterceptor.Level.BODY)

    val httpClient : OkHttpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .build()

    val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl("http://taskdemoserver.pythonanywhere.com/")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .client(httpClient)
        .build()

    val service: Service = retrofit.create(Service::class.java)

...

}

This is the errot that I get when I try to post a task.

Error 400: Bad Request

Upvotes: 3

Views: 1072

Answers (3)

dglozano
dglozano

Reputation: 6607

Even though I am not a 100% sure if this is your problem, since the server documentation you have uploaded is not complete, I am pretty confident that the problem is that the server is asking you to send the data of the task to be created using the mime type application/x-www-form-urlencoded, that's why it says formdata to the right of the Create Task endopoint in the picture you uploaded with the server documentation.

However, you are using @Body tasks: TaskListContainer, which instead is sending the information of the new task(s) as JSON data application/json. (@Body annotation)

This is what you are doing

I tested your endpoint with Postman using application/json as the Content-Type of your request. This is what Retrofit is doing right now because you used the @Body annotation in the Retrofit service.

Headers wrong Response wrong

This is what you should do instead

Now, if I send a POST request with Postman but using the form-data type instead, with a Field with key task and a String value representing the name of the task to be created, I get a a successful response.

Headers correct Response correct

To tell Retrofit to send the POST request like this, you have to define your saveTask method like this:

    interface Service {
    ...

    @Headers("user: joan")
    @FormUrlEncoded
    @POST("task")
    fun saveTask (@Field("task") taskname: String) : Call<Task>

    ...
}

You can see more information about @FormUrlEncoded annotation in the official documentation.

Also, as @YuriPopiv said, you are missing a final slash in your baseUrl. Try to set it like this .baseUrl("http://taskdemoserver.pythonanywhere.com/") or define your endpoint starting with a leading /.

From the docs:

Base URLs should always end in /. A trailing / ensures that endpoints values which are relative paths will correctly append themselves to a base which has path components.

Upvotes: 0

Yuri Popiv
Yuri Popiv

Reputation: 529

Base URLs should always end in /

Change .baseUrl("http://taskdemoserver.pythonanywhere.com") in

val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl("http://taskdemoserver.pythonanywhere.com")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .client(httpClient)
        .build()

to .baseUrl("http://taskdemoserver.pythonanywhere.com/")

Upvotes: 1

Div MoD
Div MoD

Reputation: 158

Possible you have on of these problems:

1) The server can't define the content of the response. Try to add the header with content type: @Headers("Content-Type: application/json")

2) Your base url is missing / slash at the end.

Upvotes: 0

Related Questions