Open laptou opened 8 months ago
Actually, it doesn't seem to be a timing issue. I tried adding a delay to the update from Supabase.
var authToken: String? {
didSet {
DispatchQueue.main.schedule(after: DispatchQueue.SchedulerTimeType(.now() + 20)) { [weak self] in
self?.service.invalidateConfiguration()
self?.service.wipeResources()
}
}
}
At first, the request is made with no auth token, and the view reflects that:
After twenty seconds, the update hits, and the view goes to its broken state:
Logs:
Siesta:stateChanges │ Resource(…/friends)[E] wiped
Siesta:observers │ Resource(…/friends)[] sending newData(wipe) event to 1 observer
Siesta:observers │ ↳ newData(wipe) → ClosureObserver(ObservableResource.swift:15)
Siesta:configuration │ Computing configuration for GET Resource(…/friends)[]
Siesta:configuration │ ├╴Applying config 0 [Siesta standard JSON parsing]
Siesta:configuration │ ├╴Applying config 1 [Siesta standard text parsing]
Siesta:configuration │ ├╴Applying config 2 [**]
Siesta:configuration │ └╴Resulting configuration
Siesta:configuration │ expirationTime: 30.0 sec
Siesta:configuration │ retryTime: 1.0 sec
Siesta:configuration │ progressReportingInterval: 0.05 sec
Siesta:configuration │ headers (3)
Siesta:configuration │ authorization: Bearer <JWT removed>
Siesta:configuration │ user-agent: rdvz/ios
Siesta:configuration │ accept: application/json
Siesta:configuration │ requestDecorators: 0
Siesta:configuration │ pipeline
Siesta:configuration │ ║ rawData stage (no transformers)
Siesta:configuration │ ║ decoding stage (no transformers)
Siesta:configuration │ ║ parsing stage
Siesta:configuration │ ╟ ⟨*/json */*+json⟩ Data → JSONConvertible [transformErrors: true]
Siesta:configuration │ ╟ ⟨text/*⟩ Data → String [transformErrors: true]
Siesta:configuration │ ║ model stage (no transformers)
Siesta:configuration │ ║ cleanup stage (no transformers)
Siesta:staleness │ Resource(…/friends)[] is not up to date: no error | no data
Siesta:network │ Cache request for Resource(…/friends)[]
Hi, good to see some interest in this new project. Do star the repo if you're finding it useful (as much as I hate to ask) – it helps others to see there's some level of adoption.
This is expected behaviour, and would be the same if you were using plain Siesta. You've cleared locally cached resources with wipeResources()
, but you haven't told Siesta to fetch the resource again with Resource.loadIfNeeded()
(or even load()
).
I guess since ResourceView
calls the initial loadIfNeeded
for you behind the scenes, it might have set the expectation that it will automagically fetch the resource for you whenever needed, but it's not that clever (I'm not sure that it could be).
The simplest solution would be to call self?.service.resource("/friends").loadIfNeeded()
in your didSet
immediately after wipeResources()
. A more elaborate solution might be to broadcast a theoretical authDidChange event to the rest of your app; interested parties could subscribe and take care of reloading their own resources.
Why are you seeing this?
Perhaps a more common flow is
But you have
Again, this would be the same in plain Siesta.
Let me know your thoughts / how things go.
By the way, no need to make your TypedResource a @State variable – a computed variable would be the thing. Or perhaps better (stylistically) a computed variable on your API class.
Thanks so much! I'm new to iOS development (I found out that Siesta existed less than 12 hours ago) so I appreciate you creating this library and explaining the issue. Once I get the chance to try your suggestion I'll let you know if it worked.
I guess since
ResourceView
calls the initialloadIfNeeded
for you behind the scenes, it might have set the expectation that it will automagically fetch the resource for you whenever needed, but it's not that clever (I'm not sure that it could be).
Publishers in Combine
have ways to measure whether they have active subscribers. The way that I imagine that it would work is that as soon as a resource is invalidated, it would be refreshed if it has any active subscribers (this is similar to how React Query works, for example). Do you think there is a reason why this would be a bad idea?
It's technically possible (ObservableResource
watches ResourceEvents and could do this), but my first instinct is that it's an overly general solution for a specific use case. For example, wipeResources
is usually called on logout too, so this would generate an unwanted request (which would presumably fail with a 401) – not the end of the world perhaps, but it doesn't feel quite right.
(Well, chances are that subscriptions would be getting cancelled around this time due to UI changes on logout, but perhaps not immediately.)
Thinking about vanilla Siesta, the same functionality could have been implemented there (wipeResources could cause a subsequent load if the resource has observers), but hasn't been.
I have the following code in my application:
And my
ApiService.swift
looks like this:When Supabase emits an event to point out that the user has logged in, this happens at the same time as the initial request to the backend for the friends list. The initial request is cancelled, but then the application doesn't send another request to get the data, it just does nothing and shows no data.
In the Xcode preview, where I am not logged in with Supabase, I can see the request hitting my
localhost
server, but in the Simulator, where I am logged in, no request ever reaches my server. I also tried makingHomeView.friends
a computed property, as well as inlining the call to.resource()
into my view builder; neither of these approaches worked.The logs from my app look like this: