11 lines
25 KiB
JSON
Raw Normal View History

2024-12-23 19:29:05 +00:00
{
"extension": ".swift",
"source": "import Foundation\nimport KreeRequest\n\npublic struct DevRantRequest {\n let request: KreeRequest\n let backend = DevRantBackend()\n \n public init(requestLogger: Logger) {\n self.request = KreeRequest(encoder: .devRant, decoder: .devRant, logger: requestLogger)\n }\n \n private func makeConfig(_ method: KreeRequest.Method, path: String, urlParameters: [String: String] = [:], headers: [String: String] = [:], token: AuthToken? = nil) -> KreeRequest.Config {\n var urlParameters = urlParameters\n urlParameters[\"app\"] = \"3\"\n \n if let token {\n urlParameters[\"token_id\"] = String(token.id)\n urlParameters[\"token_key\"] = token.key\n urlParameters[\"user_id\"] = String(token.userId)\n }\n \n var headers = headers\n headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n \n return .init(method: method, backend: backend, path: path, urlParameters: urlParameters, headers: headers)\n }\n \n private func makeMultipartConfig(_ method: KreeRequest.Method, path: String, parameters: [String: String] = [:], boundary: String, headers: [String: String] = [:], token: AuthToken? = nil) -> KreeRequest.Config {\n var parameters = parameters\n parameters[\"app\"] = \"3\"\n \n if let token {\n parameters[\"token_id\"] = String(token.id)\n parameters[\"token_key\"] = token.key\n parameters[\"user_id\"] = String(token.userId)\n }\n \n var headers = headers\n headers[\"Content-Type\"] = \"multipart/form-data; boundary=\\(boundary)\"\n \n return .init(method: method, backend: backend, path: path, urlParameters: parameters, headers: headers)\n }\n \n private func multipartBody(parameters: [String: String], boundary: String, imageData: Data?) -> Data {\n var body = Data()\n \n let boundaryPrefix = \"--\\(boundary)\\r\\n\"\n \n for (key, value) in parameters {\n body.appendString(boundaryPrefix)\n body.appendString(\"Content-Disposition: form-data; name=\\\"\\(key)\\\"\\r\\n\\r\\n\")\n body.appendString(\"\\(value)\\r\\n\")\n }\n \n if let imageData {\n //TODO: the image is not always jpeg. not sure if it matters here.\n body.appendString(boundaryPrefix)\n body.appendString(\"Content-Disposition: form-data; name=\\\"image\\\"; filename=\\\"image.jpeg\\\"\\r\\n\")\n body.appendString(\"Content-Type: image/jpeg\\r\\n\\r\\n\")\n body.append(imageData)\n body.appendString(\"\\r\\n\")\n }\n \n body.appendString(\"--\".appending(boundary.appending(\"--\")))\n \n return body\n }\n \n /// For endpoints with the POST method in the devRant API the url parameters need to be passed as a string in the http body rather than in the URL.\n /// The url encoding works but it might also work with other encodings like json or multipart form data.\n private func stringBody(fromUrlParameters urlParameters: [String: String]) -> String {\n String(KreeRequest.urlEncodedQueryString(from: urlParameters).dropFirst()) // dropping the first character \"?\"\n }\n}\n\npublic extension DevRantRequest {\n func logIn(username: String, password: String) async throws -> AuthToken {\n var parameters: [String: String] = [:]\n parameters[\"app\"] = \"3\"\n parameters[\"username\"] = username\n parameters[\"password\"] = password\n \n let config = makeConfig(.post, path: \"users/auth-token\")\n \n let body = stringBody(fromUrlParameters: parameters)\n \n let response: AuthToken.CodingData.Container = try await request.requestJson(config: config, string: body, apiError: DevRantApiError.CodingData.self)\n \n return response.auth_token.decoded\n }\n \n /// Gets a personalized feed of rants.\n ///\n ///
2024-12-25 20:49:05 +00:00
"review": "# 8\n\n## Bugs\n- Possible issue with the hardcoded JPEG image type label in `multipartBody` method, which assumes all images are JPEG.\n- Commented TODO for image type indicates unresolved consideration which can be critical for image handling.\n\n## Optimizations\n- Use of `.flatMap` with conditional bindings for converting images can be made more readable by leveraging optional chaining.\n- Repeated code for appending form-data parameters could be abstracted to avoid redundancy.\n- Replace string-based API path composition with constants or enums for better maintainability and to avoid string errors.\n- Implement error logging/handling for scenarios where data could unexpectedly fail to encode or decode.\n- Consider making the boundary creation more secure by ensuring no overlap with actual data content.\n\n## Good points\n- Consistent use of Swift's error-handling with `try/await` demonstrates modern Swift practices.\n- Use of extensions and private methods for code organization and encapsulation.\n- Thoughtful use of comments and TODOs to note potential improvements.\n- Separation of concerns is well managed with specific methods for each API action.\n\n## Summary\nThe codebase is overall well-structured, demonstrating a clear understanding of Swift's asynchronous programming model and best practices like encapsulation, and separation of concerns. You have highlighted potential improvement areas through comments, especially concerning image handling, which still needs resolution. Implementing improvements related to repeated patterns could enhance code maintainability and readability. \n\n## Open source alternatives\n- **Alamofire:** An HTTP networking library written in Swift that simplifies making network requests. It may be worth comparing if it provides additional benefits.\n- **Moya:** A network abstraction layer built on top of Alamofire which provides additional features to handle network requests in a more organized manner.\n- **Combine framework's URLSession:** With the Combine framework, you can handle HTTP networking tasks concurrently efficiently, simplifying error handling and response data parsing.",
2024-12-23 19:29:05 +00:00
"filename": "DevRantRequest.swift",
"path": "Sources/SwiftDevRant/DevRantRequest.swift",
"directory": "SwiftDevRant",
"grade": 8,
"size": 22105,
"line_count": 531
}