carson-katri / swift-request

Declarative HTTP networking, designed for SwiftUI
MIT License
727 stars 41 forks source link

How to extend request? #20

Closed mroushdy closed 4 years ago

mroushdy commented 4 years ago

I am new to Swift and not that familiar with the function builder, but I love this library and wanted to use it.

I was wondering how can I have a Request shared in my application that already has some things preset like the headers and the URL.

I am trying to create a centralized place for my API calls and didn't want to continue including repetitive code in the request body all over the app

carson-katri commented 4 years ago

You shouldn't need to extend Request to store them. You could try storing the Requests in an enum or struct. I'd lean toward using the enum as you won't accidentally instantiate it:

enum API {
    static let getPosts = Request { ... }
    static let getUsers = Request { ... }
    ...
}

// Call the Request
API.getPosts
        .onData { ... }
        .call()

You could also do error handling, response callbacks, etc., then call it somewhere else:

enum API {
    static let getPosts = Request { ... }.onError { ... }
    ...
}
API.getPosts.onData { ... }.call()

Let me know if you have any more questions.

mroushdy commented 4 years ago

This is amazing! Thank you. I love this library it's super simple and clean. Do you have any examples of how to use it within a ViewModel? I saw that you have an example to use it inside of a view but the code can get really messy that way.

carson-katri commented 4 years ago

I really only have one example app right now: reddit-swiftui. The OAuth branch uses more features of Request if you wanted to check that out. Request actually provides a way to use its response as an ObservableObject:

struct MyView : View {
    @ObservedObject var getPostsRes = API.getPosts.response

    var body: some View {
        Group {
            if getPostsRes.data != nil {
                // Do something with the data
            } else {
                Text("Loading...")
            }
        }
    }
}

However, I only partially got this implemented and have not tested it thoroughly, so if it's not working correctly for you, let me know and I'll see what I can do to fix it. It also has .json and .string, but I do not believe those have been implemented yet.

You could also simply wrap the requests in your ViewModel class:

class ViewModel: ObservableObject {
    @Published var postData: Data? = nil
    func getPosts() {
        API.getPosts.onData { self.postData = $0 }.call()
    }
}

Then you can call the getPosts function in onAppear or something like that.

mroushdy commented 4 years ago

Thanks man! This is very helpful and this library is amazing.

mroushdy commented 4 years ago

Any plans to add combine publishers to this? It would be great to have it support loading states out of the box.

carson-katri commented 4 years ago

Yes, it was always a plan to have good combine support, however I ran into some issues with I think it was Xcode 11.4, so I had to remove some of that quickly for it to work, and I haven’t had a chance to update it yet, and add the features I intended. But hopefully being home all the time I will be able to add in features more quickly.

Another plan is websockets, which have actually been developed to a fairly functional state, and combine is a perfect match for sockets. Hopefully I can get all of these things into the library soon.

mroushdy commented 4 years ago

sockets would be amazing!! great job

carson-katri commented 4 years ago

I'm closing this for now. RE Combine, see #21