Skip to content

Conversation

@songmilee
Copy link
Contributor

요약

  • 로그인 api 연동 및 토큰 저장 처리부 추가

리뷰 요청 사항

  • LoginStore 상에 카카오/구글 로그인 관련 DC 서버 연동
    • 애플은 별도 api가 필요합니다.
  • 토큰 저장 부를 추가하였습니다.
    • 서버 측에서 내려오는 값이 현재는 없어 플랫폼에서 제공하는 토큰을 저장합니다.

@songmilee songmilee requested a review from a team as a code owner July 21, 2023 09:08
}

struct SsoResponse: Codable {
let userId: Int64
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee

  • 특별한 경우가 아니라면 정수 자료형은 Int를 사용하는게 좋습니다. Int는 시스템 아키텍처 종류에 따라 Int64, Int32 등으로 사용됩니다.
  • Swift는 type safe한 언어라서, Int64는 Int와 충돌을 일으켜 불필요한 conversion이 필요하게 되는 단점도 있습니다.


extension LoginApi {
func loginWithSso(platformType: PlatformType, userAgent: String, accessToken: String, completion: @escaping (SsoResponse?, Error?) -> Void) {
loginSession.request(Urls.compose(path: Paths.requestSso), method: .post, parameters: ["platformType": platformType, "userAgent": userAgent, "accessToken": accessToken])
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
Method 호출부 코드가 너무 길어지면 parameter를 기준으로 적절하게 개행하시면 가독성이 더 높아질 것입니다

Comment on lines +55 to +60
switch response.result {
case .success(let result):
completion(result, nil)
case .failure(let error):
completion(nil, error)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
completion closure의 parameter type을 Result<SsoResponse, Error>으로 사용하면 코드가 더 깔끔해 질 것 같습니다



final class TokenManager {
public static let shared = TokenManager()
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
여기서 public이 꼭 필요한가요?

Comment on lines +18 to +21
if let tokenData = UserDefaults.standard.data(forKey: key) {
let token = try? JSONDecoder().decode(SsoResponse.self, from: tokenData)
self.token = token
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
guard문을 사용하면 depth가 깊어지지 않고 깔끔하게 코드를 작성할 수 있습니다.

init() {
    guard let tokenData = UserDefaults.standard.data(forKey: key) else { return }
    token = try? JSONDecoder().decode(SsoResponse.self, from: tokenData)
}

Comment on lines +25 to +30
if let data = try? JSONEncoder().encode(token) {
UserDefaults.standard.set(data, forKey: key)
UserDefaults.standard.synchronize()

self.token = token
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
여기도 guard문을 사용하면 더 간단하게 작성할 수 있어 보입니다


final class TokenManager {
public static let shared = TokenManager()
var token: SsoResponse? = nil
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
아래에 구현 방식들을 보니, token은 computed property로 만들어 사용하는게 더 편해 보이네요

final class TokenManager {
    
    var token: SsoResponse? {
        get {
            guard let tokenData = UserDefaults.standard.data(forKey: key) else { return nil }
            return try? JSONDecoder().decode(SsoResponse.self, from: tokenData)
        }
        
        set {
            guard let data = try? JSONEncoder().encode(token) else  { return }
            UserDefaults.standard.set(data, forKey: key)
        }
    }
}

이런 형태의 computed property는 property wrapper를 사용하면 더 간단하게 사용할 수도 있습니다.

final class TokenManager {
    
    @SSOResponse
    var token: SsoResponse?
}

}

extension LoginStore {
func isLogin() -> Bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
이렇게 parameter가 없고 어떤 값을 반환하기 위해 명사형으로 이름을 작성하게 되는 method들은 readonly property로 작성하면 호출부에서 더 자연스럽게 사용할 수 있습니다.

// 1.
if isLogin() { ... }

// 2.
if isLogin { ... }

return false
}

func login(email: String, password: String, completion: @escaping (Result<Bool, Error>) -> Void) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
false를 반환해야 하는 상황에서도 Error를 throw하면 어떨까요?
.success(false)가 반환되는 상황에서는 로그인 할 수 없을텐데요. '성공'한 case로 false라는 값을 반환하는 것 보다 error를 반환하는게 더 자연스럽지 않을까요?

HStack(spacing: 16) {
LoginButton(type: .kakao) {
loginStore.kakaoLogin()
loginStore.kakaoLogin { result in switch result {
Copy link
Contributor

Choose a reason for hiding this comment

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

@songmilee
여기 개행이 이상합니다

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

Successfully merging this pull request may close these issues.

3 participants