我正在尝试使用 jetpack compose + kotlin 为客户端制作一个 Android 应用程序,并为服务器端使用 Nodejs +express.js 来制作我的 RESTApi。
对于我的端点之一:
@POST /getUserIdAndName
我的服务器期望请求正文为:
{
"id": Int
}
并以以下格式给出响应:
{
"code": Int,
"body": [
{
"id": Int,
"name": String,
"photo": String
},
{
"id": Int,
"name": String,
"photo": String
},
... so on
]
}
对于我的客户端,我以这种方式对响应进行建模:
我的主要回应课:
data class DetailsResponseDto<T:ResponseBody>(
val code: Int,
val body: T?,
val message: String
)
我对此端点的响应正文:
import com.example.hola.core.domain.utils.ResponseBody
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
data class UserIdAndNameResponse(
val id : Int?,
val name : String?,
val photo: String?
)
@JsonClass(generateAdapter = true)
data class UsersList(
@Json(name = "body")
val body : List<UserIdAndNameResponse>
) : ResponseBody
端点:
@POST("/getUserIdAndName")
suspend fun getUserIdAndName(@Body myUserId: Map<String, Int>) : DetailsResponseDto<UsersList>
“ResponseBody”只是一个标记接口,我在应用程序的架构中使用了它,以便所有不同类型的响应正文可以具有相同的标识。
interface ResponseBody
当我用它从 api 获取数据时,它给出的结果是我的响应正文为空。但同时,当我检查我的服务器日志时,它给出了正确的输出。我也向 ChatGPT 询问了这个问题,但我无法得到任何也应该尊重我的应用程序的架构约束的解决方案。
限制如下:
我无法删除“ResponseBody”标记接口来简化我的响应数据类(ChatGPT 已经建议这样做),因为正如我所说,这会破坏我的架构。
我无法更改服务器端请求/响应格式,因为在使用同一端点的其他情况下,我只需要这种格式的数据。
如何解决这个问题?
我的端点的客户端实现如下:
interface GetOtherUsersDetailAbstract {
suspend fun <D>getUserIdAndNames(myUserId: Int) : Result<D, Error>
}
class EstablishNewConversations : GetOtherUsersDetailAbstract {
private val TAG = "EstablishNewConversations"
//Use retrofit to send the request
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val api : HolaAppRestApi = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
.create()
override suspend fun <D> getUserIdAndNames(myUserId: Int): com.example.hola.core.domain.utils.Result<D, Error> {
Log.d(TAG,"Get user id and names called")
val requestBody = mapOf("id" to myUserId)
return try{
val response = api.getUserIdAndName(requestBody)
Log.d(TAG, "Raw API Response: ${response}")
if (response.body != null){
detailResponseToResult(api.getUserIdAndName(requestBody))
.mapAResult { usersList: UsersList? ->
if (usersList == null) {
Log.d(TAG,"Users list is null")
UsersList(emptyList()) as D
}
Log.d(TAG,"Users list is not null: $usersList")
usersList as D
}
} else{
Log.d(TAG,"Response body is null")
Result.Error(ConversationError.NO_CONVERSATION_FOUND)
}
}catch (e:Exception){
Log.e(TAG,"Error fetching user ID and names: ${e.message}",e)
Result.Error(ConversationError.UNEXPECTED_ERROR)
}
}
}
日志是这样的:
2025-01-04 04:52:19.179 17837-17862 EstablishN...versations com.example.hola D Get user id and names called
2025-01-04 04:52:19.998 17837-17862 EstablishN...versations com.example.hola D Raw API Response: DetailsResponseDto(code=1, body=null, message=Success)
2025-01-04 04:52:19.998 17837-17862 EstablishN...versations com.example.hola D Response body is null
我的服务器端实现是:
exports.getUserIdAndName = async (req, res, next) => {
const body = req.body;
console.log("Got id as : ", body.id);
console.log("Type is : ", typeof body.id);
//Constructing base url
const baseUrl = `${req.protocol}://${req.get("host")}`;
if (!body.id) {
return res.status(400).json({
code: 0,
body: null,
error: "Invalid request. 'id' is required.",
});
}
console.log("id is correct");
try {
const userIdAndNameList = await UserDetails.getUserIdAndNameList(
body.id,
baseUrl
);
if (userIdAndNameList.code !== 1) {
console.log(`returning userList as ${JSON.stringify(userIdAndNameList)}`);
return res.status(500).json({
code: userIdAndNameList.code,
body: null,
message: userIdAndNameList.message,
});
}
console.log(`returning userList as ${JSON.stringify(userIdAndNameList)}`);
return res.status(200).json({
code: 1,
body: userIdAndNameList.data,
message: userIdAndNameList.message,
});
} catch (err) {
return res.status(500).json({
code: mapError("remoteDatabaseErr", "crudOperationErr", "unknownError"),
body: null,
message: "Some Unknown Internal error happened",
});
}
};
你的nodejs应用程序中是否实现了bodyparser?如果不是,那么body将永远为null。nodejs在控制台的输出是什么?