Fork me on GitHub
Edward Ciafardini16:11:32

Does anyone have experience using :http-xhrio recursively? I am making an API call, and each response has data along with a :next key w/ an API call as value: :next "" I have the code recursively calling the fetch, but I am having trouble making it stop when :next comes up nil. Not seeing any examples of this in my Googling. Would love any insight if you have done something like this before


Can you provide the code you already have?

Edward Ciafardini16:11:14 I know the failure event is not doing me any good. Also, I am still working out how to add all the data from the recent API call to the db without replacing what’s there (was thinking into as opposed to assoc) - Trying to make the calls work properly first.

Edward Ciafardini16:11:12

This seems to do the job in REPL (for updating db) (into [{:z 1 :v 2}] (flatten [{:a 1 :b 2}]))


This part is probably wrong because you can still be in a multi-page request:

(assoc db :loading-characters false)
This part is simply not needed because the key is used only by the very first request:
(assoc db :uri next)
Don't use flatten unless you really need to use it - it's not that obvious given its docstring. To add the results, just replace (assoc db :character-data results) with (update db :character-data merge results). If you want :character-data to be a vector of maps instead of one large map, just set the initial value to [] and replace merge with conj. The way this block is written doesn't make sense:
  (assoc db :loading-characters false)
  (assoc db :uri next)
  (assoc db :character-data results))
do returns the result of only the last statement and db is immutable. So the first two statements are practically a no-op. Given the above comments, you can simply replace the whole block with a simple (update ...) mentioned above. Regarding making it stop - does your (when (not= next nil) ...) not work properly?


I would also extract creating the arg map for :http-xhrio into its own function with only the uri argument. But overall, your approach is correct. If you end up using such a pattern more than once or twice, it will be worth it to put the whole logic in its own effect that uses :http-xhrio under the hood. This way, it'll be hidden from the business logic and you will be able to use regular callbacks instead of re-frame events.

Edward Ciafardini17:11:57

The (when (not= next nil)) is now working properly, yes. Thank you for this, I have a lot to comb over - I really appreciate it.

👍 1
Edward Ciafardini17:11:54

It isn’t so much that I want a vector of maps - but that is how the data is coming back in the responses.

Edward Ciafardini17:11:38

@U2FRKM4TW The results from the API call are coming back in the results keyword as a vector of maps: :results [{:key val :key2 val2} {:key val :key2 val2}] The update fns you suggested are yielding the same results as my initial assoc fns. The db after all the calls are made end up being the last result only (characters 78-81) Is there a way to utilize into in this context? Something like (into (:character-list db) results) I have tried a ton of things and none of them are working 🥺


Yes, of course. (update db :character-list into results). Assuming results is bound to that vector.

Edward Ciafardini17:11:09

hmm…everything I try updates the db state to the last call only.… Gonna take a break and try again later :man-shrugging:


Log not only what you receive and what you end up storing but also intermediate steps. Especially if you aren't sure what some particular function does (in that case, also make sure to read the docstring of such a function). And definitely take a look at re-frame-10x or re-frisk.

Edward Ciafardini18:11:01

Somehow, when the db is updated, the data becomes a list with the vector in it…. looking into it, but confused


If the initial value is nil, then (into nil [...]) will produce a list.

Edward Ciafardini13:11:44

@U2FRKM4TW thanks a ton for your insights. I realized that I was mistakenly referring to the response (now called res) as “db” because I didn’t fully understand the function signature. Here is the working gist (if you’re interested): Still have some cleaning up to do, but I was so happy when I got this working, just wanted to share

👍 1

Great! Just in case - this signature seems a bit off: [res [_ {:keys [results next]}]]. The first argument, res, is actually the coeffect map that's passed into every handler registered with reg-event-fx. Usually it's called ctx or even destructured in-place, like you did with {:keys [db]} (with a shorter version of {db :db}).

Edward Ciafardini14:11:50

Ah, good to know. Thanks again! I have to go over the docs again for some clarity on fn signatures.