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

[Feat] 6주차 필수과제, 심화과제, 도전과제 #11

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.sopt.and.data.local
package org.sopt.and.data.local.datasource

interface TokenLocalDataSource {
var token: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.sopt.and.data.local
package org.sopt.and.data.local.datasourceimpl

import android.content.SharedPreferences
import org.sopt.and.data.local.datasource.TokenLocalDataSource
import javax.inject.Inject

class TokenLocalDataSourceImpl @Inject constructor(
Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/org/sopt/and/data/mapper/todata/UserMapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.sopt.and.data.mapper.todata

import org.sopt.and.data.remote.model.request.LoginRequestDto
import org.sopt.and.data.remote.model.request.UserInfoUpdateRequestDto
import org.sopt.and.data.remote.model.request.UserRegistrationRequestDto
import org.sopt.and.domain.model.User

fun User.toUserRegistrationRequestDto(): UserRegistrationRequestDto = UserRegistrationRequestDto(
username = this.username,
password = this.password,
hobby = this.hobby
)

fun User.toLoginRequestDto(): LoginRequestDto = LoginRequestDto(
username = this.username,
password = this.password
)


fun User.toUserInfoUpdateRequestDto(): UserInfoUpdateRequestDto = UserInfoUpdateRequestDto(
hobby = this.hobby,
password = this.password
)
Comment on lines +20 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더 코틀린스러운 코드로 만들자면,

  • 멤버 접근 시 기본적으로 this를 생략할 수 있습니다
  • 명시적인 리턴 타입이 없어도 충분히 코드가 명확한 함수입니다 (동일한 네이밍의 Dto가 3번 반복됨)
Suggested change
fun User.toUserInfoUpdateRequestDto(): UserInfoUpdateRequestDto = UserInfoUpdateRequestDto(
hobby = this.hobby,
password = this.password
)
fun User.toUserInfoUpdateRequestDto() = UserInfoUpdateRequestDto(
hobby = hobby,
password = password
)

코드 취향일 뿐이라 그대로 하셔도 됩니다 ~~

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.and.data.mapper.todomain

import org.sopt.and.data.remote.model.response.HobbyResponseDto
import org.sopt.and.domain.model.Hobby

fun HobbyResponseDto.toDomain(): Hobby = Hobby(
hobby = this.hobby
)
Comment on lines +6 to +8

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 이러한 단일 response mapper의 경우, 따로 파일로 관리하지 않고 Dto 아래에

data class HobbyResponseDto(

) {
    fun toModel() = Hobby(
    
    )
}

처럼 활용하는 편입니당

또한 코드 정리가 안되어있는 것 같습니다 (= 뒤에 공백 2개) 습관화하거나 자동화해둡시다 ㅎㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 ..! data class에 함수를 붙이는 것 참고하겠습니다! 근데 이러니 간단한 mapper는 dto에 붙이고 프로퍼티가 4,5개쯤 되는 dto는 mapper로 분리하자니 일관성이 떨어지는 것 같기도 해서 고민이 되네요 ㅎㅎㅎ

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 사실 mapper를 안쓰고 다 따로따로 두고있기는 한데 ... ㅎㅎ 재사용성은 위 mapper가 좋아보여서요!

https://github.com/Genti2024/Genti-Android/blob/develop/data/src/main/java/kr/genti/data/dto/response/ImageDto.kt
https://github.com/Genti2024/Genti-Android/blob/develop/data/src/main/java/kr/genti/data/dto/request/CreateRequestDto.kt

저는 이런식으로 관리합니당

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 아래처럼 주로 사용합니다
dto 를 선언하는 부분에서 아래 처럼 사용합니다.

@Serializable
data class ResponseSignInDto(
    @SerialName("accessToken")
    val accessToken: String,
    @SerialName("refreshToken")
    val refreshToken: String
)

fun ResponseSignInDto.toModel() = AuthEntity(
    accessToken,
    refreshToken,
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.and.data.mapper.todomain

import org.sopt.and.data.remote.model.response.LoginResponseDto
import org.sopt.and.domain.model.Token

fun LoginResponseDto.toDomain(): Token = Token(
token = this.token
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.and.data.mapper.todomain

import org.sopt.and.data.remote.model.response.UserRegistrationResponseDto
import org.sopt.and.domain.model.UserNo

fun UserRegistrationResponseDto.toDomain(): UserNo = UserNo(
no = this.no
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.sopt.and.data.remote.datasource

import org.sopt.and.data.remote.model.base.ApiResponse
import org.sopt.and.data.remote.model.request.LoginRequestDto
import org.sopt.and.data.remote.model.request.UserRegistrationRequestDto
import org.sopt.and.data.remote.model.response.LoginResponseDto
import org.sopt.and.data.remote.model.response.UserRegistrationResponseDto

interface AuthRemoteDataSource {
suspend fun registerUser(userRegistrationRequestDto: UserRegistrationRequestDto): ApiResponse<UserRegistrationResponseDto>
suspend fun login(loginRequestDto: LoginRequestDto): ApiResponse<LoginResponseDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.sopt.and.data.remote.datasource

import org.sopt.and.data.remote.model.base.ApiResponse
import org.sopt.and.data.remote.model.request.UserInfoUpdateRequestDto
import org.sopt.and.data.remote.model.response.HobbyResponseDto
import retrofit2.Response

interface UserRemoteDataSource {
suspend fun getMyHobby(token: String): ApiResponse<HobbyResponseDto>
suspend fun getOthersHobby(token: String, userNo: Int): ApiResponse<HobbyResponseDto>
suspend fun updateUserInfo(token: String, userInfoUpdateRequestDto: UserInfoUpdateRequestDto): Response<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.sopt.and.data.remote.datasourceimpl

import org.sopt.and.data.remote.datasource.AuthRemoteDataSource
import org.sopt.and.data.remote.model.base.ApiResponse
import org.sopt.and.data.remote.model.request.LoginRequestDto
import org.sopt.and.data.remote.model.request.UserRegistrationRequestDto
import org.sopt.and.data.remote.model.response.LoginResponseDto
import org.sopt.and.data.remote.model.response.UserRegistrationResponseDto
import org.sopt.and.data.remote.service.AuthService
import javax.inject.Inject

class AuthRemoteDataSourceImpl @Inject constructor(
private val authService: AuthService
) : AuthRemoteDataSource {
override suspend fun registerUser(userRegistrationRequestDto: UserRegistrationRequestDto): ApiResponse<UserRegistrationResponseDto> =
authService.registerUser(userRegistrationRequestDto = userRegistrationRequestDto)

override suspend fun login(loginRequestDto: LoginRequestDto): ApiResponse<LoginResponseDto> =
authService.login(loginRequestDto = loginRequestDto)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sopt.and.data.remote.datasourceimpl

import org.sopt.and.data.remote.datasource.UserRemoteDataSource
import org.sopt.and.data.remote.model.base.ApiResponse
import org.sopt.and.data.remote.model.request.UserInfoUpdateRequestDto
import org.sopt.and.data.remote.model.response.HobbyResponseDto
import org.sopt.and.data.remote.service.UserService
import retrofit2.Response
import javax.inject.Inject

class UserRemoteDataSourceImpl @Inject constructor(
private val userService: UserService
): UserRemoteDataSource {
override suspend fun getMyHobby(token: String): ApiResponse<HobbyResponseDto> =
userService.getMyHobby(token = token)


override suspend fun getOthersHobby(token: String, userNo: Int): ApiResponse<HobbyResponseDto> =
userService.getOthersHobby(token = token, userNo = userNo)

override suspend fun updateUserInfo(
token: String,
userInfoUpdateRequestDto: UserInfoUpdateRequestDto
): Response<Unit> =
userService.updateUserInfo(token = token, userInfoUpdateRequestDto = userInfoUpdateRequestDto)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.sopt.and.data.remote.model.request

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class UserInfoUpdateRequestDto (
@SerialName("hobby") val hobby: String?,
@SerialName("password") val password: String?
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class GetMyHobbyResponseDto(
data class HobbyResponseDto(
@SerialName("hobby") val hobby: String
)
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package org.sopt.and.data.remote.service

import org.sopt.and.data.remote.model.base.ApiResponse
import org.sopt.and.data.remote.model.request.LoginRequestDto
import org.sopt.and.data.remote.model.request.UserRegistrationRequestDto
import org.sopt.and.data.remote.model.response.LoginResponseDto
import org.sopt.and.data.remote.model.response.UserRegistrationResponseDto
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST

interface AuthService {
@POST("user")
fun registerUser(
suspend fun registerUser(
@Body userRegistrationRequestDto: UserRegistrationRequestDto
): Call<UserRegistrationResponseDto>
): ApiResponse<UserRegistrationResponseDto>

@POST("login")
fun login(
suspend fun login(
@Body loginRequestDto: LoginRequestDto
): Call<LoginResponseDto>
): ApiResponse<LoginResponseDto>
}
25 changes: 21 additions & 4 deletions app/src/main/java/org/sopt/and/data/remote/service/UserService.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
package org.sopt.and.data.remote.service

import org.sopt.and.data.remote.model.response.GetMyHobbyResponseDto
import retrofit2.Call
import org.sopt.and.data.remote.model.base.ApiResponse
import org.sopt.and.data.remote.model.request.UserInfoUpdateRequestDto
import org.sopt.and.data.remote.model.response.HobbyResponseDto
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.PUT
import retrofit2.http.Path

interface UserService {
@GET("user/my-hobby")
fun getMyHobby(
suspend fun getMyHobby(
@Header("token") token: String
): Call<GetMyHobbyResponseDto>
): ApiResponse<HobbyResponseDto>

@GET("user/{no}/hobby")
suspend fun getOthersHobby(
@Header("token") token: String,
@Path("no") userNo: Int
): ApiResponse<HobbyResponseDto>

@PUT("user")
suspend fun updateUserInfo(
@Header("token") token: String,
@Body userInfoUpdateRequestDto: UserInfoUpdateRequestDto
): Response<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.and.data.remote.util

import org.sopt.and.data.remote.model.base.ApiResponse

fun <T> ApiResponse<T>.handleApiResponse(): Result<T> {
return if (this.result != null) Result.success(this.result)
else Result.failure(Exception("No data Available"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.sopt.and.data.repositoryimpl

import org.sopt.and.data.mapper.todata.toUserRegistrationRequestDto
import org.sopt.and.data.mapper.todomain.toDomain
import org.sopt.and.data.remote.datasource.AuthRemoteDataSource
import org.sopt.and.data.remote.model.request.LoginRequestDto
import org.sopt.and.data.remote.util.handleApiResponse
import org.sopt.and.domain.model.Token
import org.sopt.and.domain.model.User
import org.sopt.and.domain.model.UserNo
import org.sopt.and.domain.repository.AuthRepository
import javax.inject.Inject

class AuthRepositoryImpl @Inject constructor(
private val authRemoteDataSource: AuthRemoteDataSource
): AuthRepository {
override suspend fun registerUser(user: User): Result<UserNo> {
return runCatching {
authRemoteDataSource.registerUser(userRegistrationRequestDto = user.toUserRegistrationRequestDto()).handleApiResponse().getOrThrow().toDomain()
}
}
Comment on lines +17 to +21

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더 코틀린스러우려면 return 대신 =를 쓰는게 더 깔끔해보입니다 !

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

함수형 프로그래밍적인 특성이 잘 드러나는 것 같습니다! return 대신 = 사용을 지향하도록 하겠습니다😀


override suspend fun login(username: String, password: String): Result<Token> {
return runCatching {
authRemoteDataSource.login(loginRequestDto = LoginRequestDto(
username = username,
password = password
)).handleApiResponse().getOrThrow().toDomain()
}
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.sopt.and.data.repositoryimpl

import org.sopt.and.data.local.TokenLocalDataSource
import org.sopt.and.data.local.datasource.TokenLocalDataSource
import org.sopt.and.domain.repository.TokenRepository
import javax.inject.Inject

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.sopt.and.data.repositoryimpl

import org.sopt.and.data.mapper.todomain.toDomain
import org.sopt.and.data.remote.datasource.UserRemoteDataSource
import org.sopt.and.data.remote.model.request.UserInfoUpdateRequestDto
import org.sopt.and.data.remote.util.handleApiResponse
import org.sopt.and.domain.model.Hobby
import org.sopt.and.domain.repository.UserRepository
import javax.inject.Inject

class UserRepositoryImpl @Inject constructor(
private val userRemoteDataSource: UserRemoteDataSource
) : UserRepository {
override suspend fun getMyHobby(token: String): Result<Hobby> {
return runCatching {
userRemoteDataSource.getMyHobby(token = token).handleApiResponse().getOrThrow().toDomain()
}
}

override suspend fun getOthersHobby(token: String, userNo: Int): Result<Hobby> {
return runCatching {
userRemoteDataSource.getOthersHobby(token = token, userNo = userNo).handleApiResponse().getOrThrow().toDomain()
}
}

override suspend fun updateUserInfo(
token: String,
password: String?,
hobby: String?
): Result<Unit> {
return runCatching {
val response = userRemoteDataSource.updateUserInfo(
token = token,
userInfoUpdateRequestDto = UserInfoUpdateRequestDto(
password = password,
hobby = hobby
)
)
if(response.isSuccessful) {
Result.success(Unit)
} else {
Result.failure(Exception("Error : ${response.code()} ${response.message()}"))
}
}
}
}
38 changes: 0 additions & 38 deletions app/src/main/java/org/sopt/and/di/ApiFactory.kt

This file was deleted.

Loading