diff --git a/Sources/Networking/Logging/NetworkingLogger.swift b/Sources/Networking/Logging/NetworkingLogger.swift index ec29526..3832233 100644 --- a/Sources/Networking/Logging/NetworkingLogger.swift +++ b/Sources/Networking/Logging/NetworkingLogger.swift @@ -20,6 +20,10 @@ class NetworkingLogger { print("\(verb) '\(url.absoluteString)'") logHeaders(request) logBody(request) + + } + if logLevels == .debug { + logCurl(request) } } @@ -55,4 +59,34 @@ class NetworkingLogger { print("\(urlResponse.statusCode) '\(url.absoluteString)'") } } + + private func logCurl(_ urlRequest: URLRequest) { + print(urlRequest.toCurlCommand()) + } +} + +extension URLRequest { + + /** + Heavily inspired from : https://gist.github.com/shaps80/ba6a1e2d477af0383e8f19b87f53661d + */ + public func toCurlCommand() -> String { + guard let url = url else { return "" } + var command = ["curl \"\(url.absoluteString)\""] + + if let method = httpMethod, method != "GET" && method != "HEAD" { + command.append("-X \(method)") + } + + allHTTPHeaderFields? + .filter { $0.key != "Cookie" } + .forEach { command.append("-H '\($0.key): \($0.value)'")} + + if let data = httpBody, let body = String(data: data, encoding: .utf8) { + command.append("-d '\(body)'") + } + + return command.joined(separator: " \\\n\t") + } + } diff --git a/Tests/NetworkingTests/CurlLoggingTests.swift b/Tests/NetworkingTests/CurlLoggingTests.swift new file mode 100644 index 0000000..211798f --- /dev/null +++ b/Tests/NetworkingTests/CurlLoggingTests.swift @@ -0,0 +1,64 @@ +// +// CurlLoggingTests.swift +// +// +// Created by Maxence Levelu on 25/01/2021. +// + +import Foundation +import XCTest + +final class CurlLoggingTests: XCTestCase { + + func testLogGet() { + var urlRequest = URLRequest(url: URL(string: "https://jsonplaceholder.typicode.com")!) + urlRequest.httpMethod = "GET" + urlRequest.addValue("token", forHTTPHeaderField: "Authorization") + let result = urlRequest.curlString + XCTAssertEqual(result, "curl \"https://jsonplaceholder.typicode.com\" \\\n\t-H 'Authorization: token'") + } + + func testLogPost() { + var urlRequest = URLRequest(url: URL(string: + "https://jsonplaceholder.typicode.com/posts")!) + urlRequest.httpMethod = "POST" + let jsonString = """ + {"title": "Hello world"} + """ + urlRequest.httpBody = jsonString.data(using: .utf8) + let result = urlRequest.curlString + XCTAssertEqual(result, "curl \"https://jsonplaceholder.typicode.com/posts\" \\\n\t-X POST \\\n\t-d '{\"title\": \"Hello world\"}'") + } + + func testLogPut() { + var urlRequest = URLRequest(url: URL(string: + "https://jsonplaceholder.typicode.com/posts")!) + urlRequest.httpMethod = "PUT" + let jsonString = """ + {"title": "Hello world"} + """ + urlRequest.httpBody = jsonString.data(using: .utf8) + let result = urlRequest.curlString + XCTAssertEqual(result, "curl \"https://jsonplaceholder.typicode.com/posts\" \\\n\t-X PUT \\\n\t-d '{\"title\": \"Hello world\"}'") + } + + func testLogPatch() { + var urlRequest = URLRequest(url: URL(string: + "https://jsonplaceholder.typicode.com/posts")!) + urlRequest.httpMethod = "PATCH" + let jsonString = """ + {"title": "Hello world"} + """ + urlRequest.httpBody = jsonString.data(using: .utf8) + let result = urlRequest.curlString + XCTAssertEqual(result, "curl \"https://jsonplaceholder.typicode.com/posts\" \\\n\t-X PATCH \\\n\t-d '{\"title\": \"Hello world\"}'") + } + + func testLogDelete() { + var urlRequest = URLRequest(url: URL(string: + "https://jsonplaceholder.typicode.com/posts/1")!) + urlRequest.httpMethod = "DELETE" + let result = urlRequest.curlString + XCTAssertEqual(result, "curl \"https://jsonplaceholder.typicode.com/posts/1\" \\\n\t-X DELETE") + } +}