import NeedleFoundation

protocol FetchAndSaveDependency: Dependency {
    var database: Database { get }
    var httpClient: HttpClient { get }
}

class FetchAndSave: Component<FetchAndSaveDependency> {
    func run(userId: Int) async throws {
        let api: HttpClient = dependency.httpClient
        let db: Database = dependency.database

        let user = try await api.fetch(userId: userId)
        try await db.save(user: user)
    }
}

Explanation:

In Swift, we generally reach for DI frameworks to solve this. DI frameworks 
can resolve at either compile time or runtime based on the library, generally 
runtime-based DI has less boilerplate, with the obvious downside of pushing 
errors to runtime.

This method of dependency management does not compose with other effects at all 
though. We can't pull dependencies "out" of the same type that allows us to 
resolve things like async, errors, or nondeterminism. These all require separate 
syntax.