Alamofire 5 Usage Documentation Update

A large update and partial rewrite of the Alamofire Usage documentation in now in PR. You can also see the rendered markdown here. It would be great to get some community feedback, either here or on the PR, about what an introductory document should like for the library. It serves as an introduction to the top level APIs, including making requests and handling responses. Any feedback would be great!

2 Likes

Thanks Jon, I'm reading it right now.

public enum HTTPMethod: String { case connect, delete, ... }

[...] If you need to use an HTTP method that Alamofire's HTTPMethod type doesn't support, you can still set the String httpMethod property on URLRequest directly.

The closed enum was surprising (because I know there are exotic servers), but it is the sentence that had me write this message.

Is there a reason why HTTPMethod is defined as a closed enum instead of a raw representable type which accepts any string? It would allow Alamofire to support all HTTP methods out of the box, without making the life of users that remain in the strict context of RFC 7231 any more difficult:

public struct HTTPMethod: RawRepresentable {
    public var rawValue: String
    // Let users define their own methods
    public init(rawValue: String) { self.rawValue = rawValue }
    public static let connect = HTTPMethod(rawValue: "CONNECT")
    public static let delete = HTTPMethod(rawValue: "DELETE")
    ...
}

This would avoid the kind of little inconsistencies that makes the life of developers miserable: when a tiny change (supporting an exotic HTTP method) requires heavy refactoring (we can no longer rely on the HTTPMethod type in our stack).

Edit

A few lines below, I have my answer with the ParameterEncoder protocol.

With my naive suggestion, exotic methods would sometimes have to raise a fatal error:

extension HTTPMethod {
    static let exotic = HTTPMethod(rawValue: "EXOTIC")
}

// Fatal error: Please provide an explicit encoder,
// such as URLEncodedFormParameterEncoder(destination: .httpBody)
AF.request(
    "https://httpbin.org/get", 
    method: .exotic, 
    parameters: parameters)

I don't know if Alamofire makes a liberal use of fatalError and preconditions in order to spot programmer mistakes (an ever-hot topic), so I won't elaborate more. I just want to say that in my humble opinion, this is still better than the closed enum, because of my argument above (a tiny change in an app shouldn't require heavy refactoring).

You're right. HTTPMethod is one of the original types of Alamofire and hasn't changed much in that time. Creating a fully fleshed out type would probably be fairly simple, but like HTTP headers, I would likely want to create a case-insensitive implementation that allowed get and GET to be the same method. And yes, as you noted, it would make some of our method checks more complex.

In the meantime, switching from HTTPMethod to String in any compositional APIs should allow users to use any headers they want, while still being able to use the HTTPMethod values.

Any other feedback?

@gwendal.roue I've created a PR to unfreeze HTTPMethod. Turns out it wasn't much of an issue and should lead to more flexibility.

Alamofire 5 has removed all inadvertent assertions (force unwraps) but making the appropriate APIs throwing, but we do still use a few preconditions internally to ensure the internal state we use to track Request lifetimes is always consistent.

Thanks Jon! I'm happy it was a simple change :-) Reading this doc has removed all my questions :+1:

I have another question regarding the robustness of auto-starting requests: I have witnessed in a couple occasions a race condition that happens in Alamofire 4 and the first betas of Alamofire 5:

AF.request(...)
    .validate(...) // too late, response may already have been received
    .responseXXX { ... } // process unvalidated response 😨

I now always set the startRequestsImmediately session flag to false, and always start my requests after they have been fully defined. This prevents the race completely.

I have to write my concern more precisely, in a proper Github issue. But does what I say ring a bell to you?

@Jon_Shier, actually both https://github.com/Alamofire/Alamofire/pull/2862 and https://github.com/Alamofire/Alamofire/pull/2810 (especially #2862) look like they are related. But I'm still wondering if the only way to get the truly non-brainer Alamofire everybody wants is to set startRequestsImmediately to false. "Once bitten, twice shy" say some people :sweat_smile:

The race between adding a validator and processing a response is still there, but should now be much more rare due to the entire request pipeline being async in Alamofire 5. Adding a validator now locks the Request's internal state while it's being added, which means it should usually win the race. But yes, these sorts of APIs are inherently racy, and it's always been our recommendation that anyone encountering issues turn off automatic start.

Automatic start was one of the original reasons for the creation of Alamofire, so for better or worse it's an expected part of the library now. I think we've fixed most of the issues people have seen with the internal rewrite that's part of Alamofire 5.

Thanks Jon. That's very clear. I'll preventively keep pushing on the safe handle, then :slight_smile:

No more comment on the great Alamofire 5! Let's have other people chime in!

Terms of Service

Privacy Policy

Cookie Policy