11 lines
25 KiB
Markdown
11 lines
25 KiB
Markdown
|
{
|
||
|
"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 ///
|
||
|
"review": "**8**\n\n# Bugs\n- **Image Format Assumption:** In the `multipartBody` function, the image is assumed to always be a JPEG, which might not be the case leading to incorrect content types.\n- **Unnecessary \"plat\" and \"nari\" Parameters:** The `getRantFeed` function contains parameters whose purpose is unknown, which may affect the API call results.\n- **Unsafe Force Unwrapping:** In `appendString`, force unwrapping data from string conversion can lead to runtime crashes if `nil`.\n\n# Optimizations\n- **Error Handling:** Implement robust error handling instead of force unwrapping in `appendString`.\n- **String Valuation Improvements:** Improve the boundary string concatenation for better readability.\n- **Use Codable Protocols:** Consider utilizing Swift's `Codable` protocol more extensively to simplify JSON parsing and mapping.\n\n# Good Points\n- **Asynchronous Functionality:** Makes good use of Swift\u2019s async/await features for handling asynchronous operations.\n- **Clean Structuring:** The code is neatly structured with clear sections for different API calls.\n- **Encapsulation:** The logic for request configuration is encapsulated in private methods reducing code duplication.\n\n# Summary\nThe code is well-structured, with a good use of Swift's modern async/await pattern facilitating asynchronous network requests. The functionality is well-encapsulated in functions, maintaining a clean code structure. However, some assumptions, especially regarding image data handing and forced unwrapping, might lead to runtime issues. Adding comprehensive error checking and handling could be beneficial. Overall, the code serves its purpose well but could improve in terms of robustness.\n\n# Open source alternatives\n- **Alamofire**: A robust library for network requests in Swift, providing many utilities out of the box.\n- **Moya**: Built on top of Alamofire, Moya provides an abstraction over network requests, simplifying API interaction.\n- **HTTPNetworking in SwiftNIO**: For more control and performance in building HTTP clients, especially for asynchronous I/O operations.",
|
||
|
"filename": "DevRantRequest.swift",
|
||
|
"path": "Sources/SwiftDevRant/DevRantRequest.swift",
|
||
|
"directory": "SwiftDevRant",
|
||
|
"grade": 8,
|
||
|
"size": 22105,
|
||
|
"line_count": 531
|
||
|
}
|