Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to handle responses with 200 **AND** 204 (No Content) #44

Closed
clmnin opened this issue Jul 9, 2021 · 3 comments
Closed

How to handle responses with 200 **AND** 204 (No Content) #44

clmnin opened this issue Jul 9, 2021 · 3 comments

Comments

@clmnin
Copy link

clmnin commented Jul 9, 2021

We can handle a 204 with

suspend fun updateStatusOnServer(): NetworkResponse<Unit, ErrorType>

But here the response can only be Unit. But what if I can have a 200 responses when there is new content and 204 when there is no new content?

@Sharkaboi
Copy link

I think it will return a ServerError as stated here if the response has success code, but the body is null and return class isn't Unit.
So, if you wanted to handle that case you could do something like this :

when (result) {
        is NetworkResponse.Success -> {
            // Handle successful response (204)
        }
        is NetworkResponse.ServerError -> {
            if(result.code == 200){
                // handle special case
            }
            // Handle normal server error
        }
        is NetworkResponse.NetworkError -> {
            // Handle network error
        }
        is NetworkResponse.UnknownError -> {
            // Handle other errors
        }
    }

@clmnin
Copy link
Author

clmnin commented Jul 21, 2021

@Sharkaboi Yes this works. But I was asking if this would be a good feature to have. Maybe raise a PR. But got engaged with other stuff.
Thanks again.

@clmnin clmnin closed this as completed Jul 21, 2021
@haroldadmin
Copy link
Owner

Consider this example:

interface PostsService {
  @GET("/")
  suspend fun getPost(): NetworkResponse<Post, ErrorResponse>
}

When the server responds with a 2xx status code and a Post in the body, everything works well, but things get complicated when it responds with a null body.

In this scenario we have to decide whether you expected a null body or not.

  • If you expected it, then you should indicate it with a Unit success type, and the library happily treat it as a success case.
  • If you didn't expect it, then this is an invalid response and we therefore map it to a NetworkResponse.ServerError.

Things get more complicated if the server can respond with both types of bodies in the same API call. For this scenario:

  • If you indicate the response body as Unit, you lose access to the response content from the server
  • If you indicate the response body as something other than Unit, we consider it an error for empty responses.

So the real problem here is that you lose access to the response content for Unit bodies. The upcoming v5 release will provide a better way to deal with this problem by bundling every NetworkResponse.Success value with the raw Retrofit response. You can use this raw response to manually deserialize the body to access the underlying content.

// The new Success class
data class Success<S, E>(val body: S, val response: Response<*>): NetworkResponse<S, E>

interface PostsService {
  @GET("/")
  suspend fun getPost(): NetworkResponse<Unit, ErrorResponse>
}

when (val postResponse  = service.getPost()) {
  is NetworkResponse.Success -> {
    if (postResponse.code != 204) {
      val rawBody = postResponse.response.rawBody()
      // Manually parse the raw body to access the response
    }
  }
  is NetworkResponse.Error -> { ... }
}

You can then always specify the return type as Unit, but access the raw body if required.

Here's an example of how to deserialize the raw body using the kotlinx.serialization library:

@Serializable
data class Post(...)

val rawBody = postResponse.response.raw().body
val decoded = Json.decodeFromString(Post.serializer(), rawBody.string())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants