Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2dee620

Browse files
fix: handle missing usertheme_preference on sign in (#91)
coder/coder#16564 has the Coder server no longer send the `theme_preference` field in a `/api/v2/user` response. The Swift `JSONDecoder` requires that a missing field be explicitly marked as optional, else the deserialization fails. To make it less likely this happens again, we'll only require `id` and `username` be present.We'll do the same for the other SDK types and only require the minimum fields the app needs be present.This PR also improves the error message on any decoding error:<img width="259" alt="Screenshot 2025-03-06 at 1 35 33 pm" src="https://github.com/user-attachments/assets/0fef147c-29ad-41bf-9aff-29651ff6b796" />
1 parentae51d0e commit2dee620

File tree

5 files changed

+29
-106
lines changed

5 files changed

+29
-106
lines changed

‎Coder Desktop/Coder DesktopTests/LoginFormTests.swift

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,7 @@ struct LoginTests {
9393

9494
letuser=User(
9595
id:UUID(),
96-
username:"admin",
97-
avatar_url:"",
98-
name:"admin",
99-
email:"admin@coder.com",
100-
created_at:Date.now,
101-
updated_at:Date.now,
102-
last_seen_at:Date.now,
103-
status:"active",
104-
login_type:"none",
105-
theme_preference:"dark",
106-
organization_ids:[],
107-
roles:[]
96+
username:"admin"
10897
)
10998

11099
tryMock(

‎Coder Desktop/CoderSDK/Client.swift

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public struct Client {
4444
throw.network(error)
4545
}
4646
guardlet httpResponse= respas?HTTPURLResponseelse{
47-
throw.unexpectedResponse(data)
47+
throw.unexpectedResponse(String(data: data, encoding:.utf8)??"<non-utf8 data>")
4848
}
4949
returnHTTPResponse(resp: httpResponse, data: data, req: req)
5050
}
@@ -72,7 +72,7 @@ public struct Client {
7272

7373
func responseAsError(_ resp:HTTPResponse)->ClientError{
7474
do{
75-
letbody=tryClient.decoder.decode(Response.self, from: resp.data)
75+
letbody=trydecode(Response.self, from: resp.data)
7676
letout=APIError(
7777
response: body,
7878
statusCode: resp.resp.statusCode,
@@ -81,7 +81,24 @@ public struct Client {
8181
)
8282
return.api(out)
8383
}catch{
84-
return.unexpectedResponse(resp.data.prefix(1024))
84+
return.unexpectedResponse(String(data: resp.data, encoding:.utf8)??"<non-utf8 data>")
85+
}
86+
}
87+
88+
// Wrapper around JSONDecoder.decode that displays useful error messages from `DecodingError`.
89+
func decode<T>(_:T.Type, from data:Data)throws(ClientError)->Twhere T:Decodable{
90+
do{
91+
returntryClient.decoder.decode(T.self, from: data)
92+
}catchletDecodingError.keyNotFound(_, context){
93+
throw.unexpectedResponse("Key not found:\(context.debugDescription)")
94+
}catchletDecodingError.valueNotFound(_, context){
95+
throw.unexpectedResponse("Value not found:\(context.debugDescription)")
96+
}catchletDecodingError.typeMismatch(_, context){
97+
throw.unexpectedResponse("Type mismatch:\(context.debugDescription)")
98+
}catchletDecodingError.dataCorrupted(context){
99+
throw.unexpectedResponse("Data corrupted:\(context.debugDescription)")
100+
}catch{
101+
throw.unexpectedResponse(String(data: data.prefix(1024), encoding:.utf8)??"<non-utf8 data>")
85102
}
86103
}
87104
}
@@ -119,7 +136,7 @@ public struct FieldValidation: Decodable, Sendable {
119136
publicenumClientError:Error{
120137
case api(APIError)
121138
case network(anyError)
122-
case unexpectedResponse(Data)
139+
case unexpectedResponse(String)
123140
case encodeFailure(anyError)
124141

125142
publicvardescription:String{
@@ -129,7 +146,7 @@ public enum ClientError: Error {
129146
caselet.network(error):
130147
error.localizedDescription
131148
caselet.unexpectedResponse(data):
132-
"Unexpectedor non HTTPresponse:\(data)"
149+
"Unexpected response:\(data)"
133150
caselet.encodeFailure(error):
134151
"Failed to encode body:\(error.localizedDescription)"
135152
}

‎Coder Desktop/CoderSDK/Deployment.swift

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,12 @@ public extension Client {
66
guard res.resp.statusCode==200else{
77
throwresponseAsError(res)
88
}
9-
do{
10-
returntryClient.decoder.decode(BuildInfoResponse.self, from: res.data)
11-
}catch{
12-
throw.unexpectedResponse(res.data.prefix(1024))
13-
}
9+
returntrydecode(BuildInfoResponse.self, from: res.data)
1410
}
1511
}
1612

17-
publicstructBuildInfoResponse:Encodable,Decodable,Equatable,Sendable{
18-
publicletexternal_url:String
13+
publicstructBuildInfoResponse:Codable,Equatable,Sendable{
1914
publicletversion:String
20-
publicletdashboard_url:String
21-
publiclettelemetry:Bool
22-
publicletworkspace_proxy:Bool
23-
publicletagent_api_version:String
24-
publicletprovisioner_api_version:String
25-
publicletupgrade_message:String
26-
publicletdeployment_id:String
2715

2816
// `version` in the form `[0-9]+.[0-9]+.[0-9]+`
2917
publicvarsemver:String?{

‎Coder Desktop/CoderSDK/User.swift

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,68 +6,19 @@ public extension Client {
66
guard res.resp.statusCode==200else{
77
throwresponseAsError(res)
88
}
9-
do{
10-
returntryClient.decoder.decode(User.self, from: res.data)
11-
}catch{
12-
throw.unexpectedResponse(res.data.prefix(1024))
13-
}
9+
returntrydecode(User.self, from: res.data)
1410
}
1511
}
1612

1713
publicstructUser:Encodable,Decodable,Equatable,Sendable{
1814
publicletid:UUID
1915
publicletusername:String
20-
publicletavatar_url:String
21-
publicletname:String
22-
publicletemail:String
23-
publicletcreated_at:Date
24-
publicletupdated_at:Date
25-
publicletlast_seen_at:Date
26-
publicletstatus:String
27-
publicletlogin_type:String
28-
publiclettheme_preference:String
29-
publicletorganization_ids:[UUID]
30-
publicletroles:[Role]
3116

3217
publicinit(
3318
id:UUID,
34-
username:String,
35-
avatar_url:String,
36-
name:String,
37-
email:String,
38-
created_at:Date,
39-
updated_at:Date,
40-
last_seen_at:Date,
41-
status:String,
42-
login_type:String,
43-
theme_preference:String,
44-
organization_ids:[UUID],
45-
roles:[Role]
19+
username:String
4620
){
4721
self.id= id
4822
self.username= username
49-
self.avatar_url= avatar_url
50-
self.name= name
51-
self.email= email
52-
self.created_at= created_at
53-
self.updated_at= updated_at
54-
self.last_seen_at= last_seen_at
55-
self.status= status
56-
self.login_type= login_type
57-
self.theme_preference= theme_preference
58-
self.organization_ids= organization_ids
59-
self.roles= roles
60-
}
61-
}
62-
63-
publicstructRole:Encodable,Decodable,Equatable,Sendable{
64-
publicletname:String
65-
publicletdisplay_name:String
66-
publicletorganization_id:UUID?
67-
68-
publicinit(name:String, display_name:String, organization_id:UUID?){
69-
self.name= name
70-
self.display_name= display_name
71-
self.organization_id= organization_id
7223
}
7324
}

‎Coder Desktop/CoderSDKTests/CoderSDKTests.swift

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,9 @@ import Testing
77
structCoderSDKTests{
88
@Test
99
func user()asyncthrows{
10-
letnow=Date.now
1110
letuser=User(
1211
id:UUID(),
13-
username:"johndoe",
14-
avatar_url:"https://example.com/img.png",
15-
name:"John Doe",
16-
email:"john.doe@example.com",
17-
created_at: now,
18-
updated_at: now,
19-
last_seen_at: now,
20-
status:"active",
21-
login_type:"email",
22-
theme_preference:"dark",
23-
organization_ids:[UUID()],
24-
roles:[
25-
Role(name:"user", display_name:"User", organization_id:UUID()),
26-
]
12+
username:"johndoe"
2713
)
2814

2915
leturl=URL(string:"https://example.com")!
@@ -50,15 +36,7 @@ struct CoderSDKTests {
5036
@Test
5137
func buildInfo()asyncthrows{
5238
letbuildInfo=BuildInfoResponse(
53-
external_url:"https://example.com",
54-
version:"v2.18.2-devel+630fd7c0a",
55-
dashboard_url:"https://example.com/dashboard",
56-
telemetry:true,
57-
workspace_proxy:false,
58-
agent_api_version:"1.0",
59-
provisioner_api_version:"1.2",
60-
upgrade_message:"foo",
61-
deployment_id:UUID().uuidString
39+
version:"v2.18.2-devel+630fd7c0a"
6240
)
6341

6442
leturl=URL(string:"https://example.com")!

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp