3

Ive been googling and trying for the last few days regarding the automatic escaping of forward slashes of alamofire.

(Where "/path/image.png" becomes "\/path\/image.png")

However all the answers either point towards a solution if your using swiftyJson, sending via a httpBody or using the Alamofire Parameter Class.

https://github.com/SwiftyJSON/SwiftyJSON/issues/440

Im not using SwiftyJson and feel to install the API just to resolve the issue is a case of hitting the nail with a sledge hammer.

Anyway.

My issue is whenever I'm trying to send parameters to an API, Alamofire's JSONEncoding.default kindly escapes forward slashes. I don't want Alamofire to do this.

In my case I want to send the following parameter and have Alamofire ignore the forward slashes

let parameter : Parameters =  ["transaction": "/room/120"] 

Alamofire.request(endPoint , method: .post, parameters: parameter ,encoding: JSONEncoding.default , headers: header).validate(statusCode: 200..<300).responseObject { (response: DataResponse<SomeModel>) in

}

Maybe creating a custom json encoder is the way to do this but I find very little documentation on how best to go about it.

I have also tried

let parameter : [String : Any] =  ["transaction": "/room/120"] 

Alamofire.request(endPoint , method: .post, parameters: parameter ,encoding: JSONEncoding.default , headers: header).validate(statusCode: 200..<300).responseObject { (response: DataResponse<SomeModel>) in
Really appreciate all your help and suggestions.

Ive even read that the backend should be able to deal with the escaping characters, but its working fine for the android dev. Thus if its my code that is sending the wrong data, then I feel it should resolved at the source

Thomas

Tom
  • 2,358
  • 1
  • 15
  • 30
  • I am having the exact same headache – yogipriyo Nov 27 '17 at 01:00
  • 1
    I'm not sure how familiar you are with the JSON standards ([ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf)) but `"/"` __should be escaped__ in a JSON string, so the `"\/"` is correct, perfectly conforms the standards – you should not worry about how other platforms interpreting any standard, you should always go back to the source – as you just said. – holex Feb 08 '18 at 10:54

1 Answers1

9

I had the same issue and decided to go the way of the custom JSON encoder. There are probably better/shorter ways than this but seeing as I'm a Swift noob, it does it's job and is good enough for me.

I simply looked up the used JSONEncoder used by Alamofire and made my own:

public struct JSONEncodingWithoutEscapingSlashes: ParameterEncoding {

// MARK: Properties

/// Returns a `JSONEncoding` instance with default writing options.
public static var `default`: JSONEncodingWithoutEscapingSlashes { return JSONEncodingWithoutEscapingSlashes() }

/// Returns a `JSONEncoding` instance with `.prettyPrinted` writing options.
public static var prettyPrinted: JSONEncodingWithoutEscapingSlashes { return JSONEncodingWithoutEscapingSlashes(options: .prettyPrinted) }

/// The options for writing the parameters as JSON data.
public let options: JSONSerialization.WritingOptions

// MARK: Initialization

/// Creates a `JSONEncoding` instance using the specified options.
///
/// - parameter options: The options for writing the parameters as JSON data.
///
/// - returns: The new `JSONEncoding` instance.
public init(options: JSONSerialization.WritingOptions = []) {
    self.options = options
}

// MARK: Encoding

/// Creates a URL request by encoding parameters and applying them onto an existing request.
///
/// - parameter urlRequest: The request to have parameters applied.
/// - parameter parameters: The parameters to apply.
///
/// - throws: An `Error` if the encoding process encounters an error.
///
/// - returns: The encoded request.
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
    var urlRequest = try urlRequest.asURLRequest()

    guard let parameters = parameters else { return urlRequest }

    do {
        let data = try JSONSerialization.data(withJSONObject: parameters, options: options)

        let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue)?.replacingOccurrences(of: "\\/", with: "/")

        if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
            urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
        }

        urlRequest.httpBody = string!.data(using: .utf8)
    } catch {
        throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
    }

    return urlRequest
}

/// Creates a URL request by encoding the JSON object and setting the resulting data on the HTTP body.
///
/// - parameter urlRequest: The request to apply the JSON object to.
/// - parameter jsonObject: The JSON object to apply to the request.
///
/// - throws: An `Error` if the encoding process encounters an error.
///
/// - returns: The encoded request.
public func encode(_ urlRequest: URLRequestConvertible, withJSONObject jsonObject: Any? = nil) throws -> URLRequest {
    var urlRequest = try urlRequest.asURLRequest()

    guard let jsonObject = jsonObject else { return urlRequest }

    do {
        let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options)

        let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue)?.replacingOccurrences(of: "\\/", with: "/")

        if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
            urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
        }

        urlRequest.httpBody = string!.data(using: .utf8)
    } catch {
        throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
    }

    return urlRequest
}
}

Probably should include some more error handling too :)

Finally I could use it like the standard JSONEncoder:

Alamofire.request(EndpointsUtility.sharedInstance.cdrStoreURL, method: .post, parameters: payload, encoding: JSONEncodingWithoutEscapingSlashes.prettyPrinted)...

hope it helps!

csim
  • 610
  • 7
  • 11