Skip to content

make API non-throwing #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Conversation

tomerd
Copy link
Contributor

@tomerd tomerd commented Jul 10, 2019

motivation: cleaner API for users

changes:

  • make request initializer optional instead of throwing
  • http "sugar" methods (get, post, etc) no longer need to be throwing
  • fix schema logic to be non-case sensitive
  • made request object version, method and url immutable
  • made request object scheme and host internal
  • adjusted redirect ahndler implementation to stricter request immutabllity
  • adjust and add tests

motivation: cleaner API for users

changes:
* make request initializer optional instead of throwing
* http "sugar" methods (get, post, etc) no longer need to be throwing
* fix schema logic to be non-case sensitive
* made request object version, method and url immutable
* made request object scheme and host internal
* adjusted redirect ahndler implementation to stricter request immutabllity
* adjust and add tests
@tomerd tomerd requested a review from weissi July 10, 2019 01:34
guard let scheme = url.scheme else {
throw HTTPClientError.emptyScheme
public init?(url: URL, version: HTTPVersion = HTTPVersion(major: 1, minor: 1), method: HTTPMethod = .GET, headers: HTTPHeaders = HTTPHeaders(), body: Body? = nil) {
guard let scheme = url.scheme?.lowercased() else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree that this is much nicer as a user, but we're sacrificing the type of error for a "this worked or not" without the context on what the problem was. I think I'd prefer to keep the granular errors vs. checking for nil instead, but if there's already been discussion (or others have the other preference!) happy to defer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't follow all of the discussions here recently... but would it be an option to add address the above concern by adding static func validated(<mirror init's param list>) throws -> Request, users get to choose then, and if it was discussed that the nil is "nicer" then that's indeed the default still 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great call, that helps with surfacing the specific issue if someone really wants it. 🧠

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find nil-returning functions like this profoundly frustrating as they're almost impossible to debug. It's very annoying to look at something you're confident is valid data and to have the program tell you that it is not valid, without any explanation as to why.

I'd be strongly -1 on this without at least the option for a constructor that gives me better diagnostics, but frankly I'm not sure if the convenience of the nil return is worth it for the inevitable failure of debuggability down the line.

Copy link
Contributor Author

@tomerd tomerd Jul 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lukasa this PR originated as a simpler and safer way compared to #56. totally agree on the information loss point as brought up by @Yasumoto and @ktoso ^^, and think we can keep the API throwing - i was just mirroring #56 in that sense. that said, the existing throwing code has a validation/mutability race that needs to be addressed and this PR demonstrates that part

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the throwing version: #67

public var headers: HTTPHeaders
public var body: Body?

internal let scheme: String
internal let host: String
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if user will modify the url parameter? And new url doesn't contain a host?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@artemredkin url is a let in this PR

@t089
Copy link
Contributor

t089 commented Jul 10, 2019

Not sure if this was discussed already, but how about this: if the given URL is not suitable for firing off the request, instead of throwing or returning nil, create an appropriate Error and immediately fail the Promise/Task with this error? This way the API is very easy to use (no do/catch, no optional check) and in the rare case that for some reason the URL is incomplete it will be catched by the error handling that is anyhow necessary when doing network requests.

@artemredkin
Copy link
Collaborator

@t089 like in #56 ?

@t089
Copy link
Contributor

t089 commented Jul 10, 2019

@artemredkin Ok, yes, sorry I got confused. Actually both PRs do this already right? The only remaining question is how to represent a validated URL as an internal type, if I understand correctly?

Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this patch right now: I don't know if I consider making request non-throwing should be considered a goal at all.

guard let scheme = url.scheme else {
throw HTTPClientError.emptyScheme
public init?(url: URL, version: HTTPVersion = HTTPVersion(major: 1, minor: 1), method: HTTPMethod = .GET, headers: HTTPHeaders = HTTPHeaders(), body: Body? = nil) {
guard let scheme = url.scheme?.lowercased() else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find nil-returning functions like this profoundly frustrating as they're almost impossible to debug. It's very annoying to look at something you're confident is valid data and to have the program tell you that it is not valid, without any explanation as to why.

I'd be strongly -1 on this without at least the option for a constructor that gives me better diagnostics, but frankly I'm not sure if the convenience of the nil return is worth it for the inevitable failure of debuggability down the line.

method = .GET
body = nil
headers.remove(name: "Content-Length")
headers.remove(name: "Content-Type")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this whitespace about?

@Lukasa
Copy link
Collaborator

Lukasa commented Jul 10, 2019

As @weissi pointed out to me, if you want to replace a function that is throws with one that returns nil, there's a keyword for that: try?. It is always possible to trivially transform a throwing function to a nil-returning one. However, it is not possible to get the throwing information back.

Right now we notify the user of what exactly we think they did wrong, and I think it's simply the wrong thing to do to hide this information.

@weissi weissi requested review from artemredkin and Lukasa July 17, 2019 09:52
Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remain opposed to merging this patch, and prefer making further improvements to #67.

(I'm adding this because a re-review was requested, not because I think anyone needs the update).

@weissi weissi requested a review from Lukasa July 17, 2019 10:00
Copy link
Collaborator

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remain opposed to merging this patch, and prefer making further improvements to #67.

(I'm adding this because a re-review was requested, not because I think anyone needs the update).

@tomerd
Copy link
Contributor Author

tomerd commented Jul 18, 2019

this is an older proposal, the discussion is happening in #67

@tomerd tomerd closed this Jul 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants