How can I get all Actions for a Board using Trello's Rest API? - rest

I want to get all the actions for a board, but Trello limits the results to 1000. I understand the correct way to deal with this is to paginate. I've tried both before and page as keywords:
Basic Call:
https://api.trello.com/1/board/[boardID]/
?key=[key]&token=[token]
&actions=commentCard&actions_limit=1000
Alternatives:
Before:
https://api.trello.com/1/board/[boardID]/
?key=[key]&token=[token]
&actions=commentCard&actions_limit=1000&
before=[oldest_returned_action's_date]
Page:
https://api.trello.com/1/board/[boardID]/
?key=[key]&token=[token]
&actions=commentCard&actions_limit=1000&
page=[page_number]
The result never varies --- I always get back [limit] number of actions, and they're always the same no matter the call. I checked the dates in what was returned and they certainly don't respect the before parameter. I even tried lowering the limit to make sure I wasn't trying to return more than I possessed. The problem persists.
How can I correctly get all actions for a Trello board?

Actions are in reverse chronological order (newest-to-oldest), so to page through the actions on a board, you would use something like:
curl "https://api.trello.com/1/boards/${BOARD_ID}/actions/?key=${TRELLO_API_KEY}&token=${TRELLO_TOKEN}&limit=1000"
then, from the last element of the array returned by the the above, select the date or id and pass that as the before parameter in the next call, e.g.:
curl "https://api.trello.com/1/boards/${BOARD_ID}/actions/?key=${TRELLO_API_KEY}&token=${TRELLO_TOKEN}&limit=1000&before=${DATE_OR_ID_OF_LAST_ACTION}"
and repeat, passing in either the id or date of the last action as the subsequent before parameter.
References:
Paging
Board Actions
Actions Nested Resource

Related

patch endpoint naming and realisation

We have rest resource
/tasks/{task-type}
and only GET methods available.
GET /tasks/{task-type}
GET /tasks/{task-type}/{id}
Task entity contains meta info like created, finished, status, ref key and try counts for scheduled tasks.
Now we faced with problem, when task may contains incorrect data and its execution always failed.
Due to scheduler invoked tasks every 5 min there are a lot of errors in logs and largest try counts around 500k. The solution i found is to limit try_count to five (for example). And now we need way to manual discard try-count to zero. So i found two solutions:
1.
PATCH /tasks/{task-type}/{id}/discard-try-count - no response body
This solution look pretty simple, but violates the REST convention, because we use action(verb) in naming. But if we need to change other fields, then we will make a lot of endpoints in this style.
2a.
PATCH /tasks/{task-type}/{id}
body:
{
"tryCounts": int
}
This looks like REST want to see it and we can easy add new fields to modify, but now client can set any value for tryCount.
2b
PATCH /tasks/{task-type}/{id}
body:
{
"tryCounts": int // validate that try count can be only zero
}
Differs from the previous one by the presence of validation.
This looks like the most reliable solution. Is it really the best fit?
The non-verb convention is not a standard, you can violate it if you want to, though it can be worked around with very simple stuff, just convert the verb into a noun and you will be ok, something like:
POST /tasks/{task-type}/{id}/try-count-discarding
Another way is setting the try count to zero:
PUT /tasks/{task-type}/{id}/try-count 0
Yet another solution is combining the two, which I like the most:
PATCH /tasks/{task-type}/{id}/try-count {"op": "reset"}
Or another variant:
PATCH /tasks/{task-type}/{id} {"op": "discard-try-count"}

How to prevent cy.get from "snapshotting" a list before it's sorted

Not the best title, but here's my challenge. I have a list on my page that can be sorted, and I want a Cypress test that checks that it works as expected. So imagine this test:
/* 1 */ cy.get('.list-item').eq(0).should('have.text', 'A');
/* 2 */ cy.get('.list-item').eq(-1).should('have.text', 'Z');
// Code that triggers sorting to change from asc to desc
/* 3 */ cy.get('.list-item').eq(0).should('have.text', 'Z');
/* 4 */ cy.get('.list-item').eq(-1).should('have.text', 'A');
Looks simple, but there's a slight delay when the sorting happens, so the UI isn't updated immediately.
I'm not sure if it's the cy.get or the eq function which causes it, but the problem is that line 3 "captures" the first element in the list, which is still 'A', and then tries to assert that the text is 'Z'. And when the list is reordered, this "captured" element doesn't actually change, it's just moved in the DOM, so the assertion still tries to assert that same element 'A', which in the DOM is actually the last element now, is 'Z', which it obviously isn't and shouldn't be.
If I insert a cy.wait(100) before 3, then it works as expected, but obviously I do not want to have a random wait in my test, so how do I solve this?
How do I check what the first and last elements are in a situation like this, when Cypress captures the DOM elements before they're reordered, without inserting an arbitrary wait? 😕
Actual case
Support app, showing a list of the 5 most recently viewed clients
Need to test that, when visiting for example number 3 in that list, it is moved to the top
The "code that triggers sorting" is actually a route navigation event:
There's a listener (React useEffect hook) on route changes.
When route changes, it updates the list of recently viewed client ids, which is stored in local storage.
When the list in local storage changes, the component showing the list first waits 750ms (so it's less confusing for user, but turned down to 10ms in Cypress tests), then updates (re-sorts) the list.
And since the list only contains ids, each tile will then async load the name and some more stuff to display on the list item.
So... the delay is actually more than just a UI update. There's routing, local storage and async requests involved too. 🎉
You need to merge cy.get(...) and .eq into a single selector to make sure it retries the assertion .should('have.text', 'Z') after resorting. Read about it https://on.cypress.io/retry-ability#Merging-queries - right now it grabs the list and then only retries .eq() command, which is too late. You could also rewrite your code to get the first and last elements using single .should(cb) https://on.cypress.io/should#Function - the example in the docs really fits your use case.
I am taking a wild shot here, but perhaps in the trigger to sort you could use then.
cy.get('.list-item').eq(0).should('have.text', 'A');
cy.get('.list-item').eq(-1).should('have.text', 'Z');
// Code that triggers sorting to change from asc to desc
cy.get("#id-to-sort").click().then(()=>{
cy.get('.list-item').eq(0).should('have.text', 'Z');
cy.get('.list-item').eq(-1).should('have.text', 'A');
})

How to filter by both text and property in Chrome DevTool's network panel?

I want to filter Chrome DevTool's network panel by the method property and text in the URL. For example, if I am searching for the text chromequestion in the URL and only HTTP GET requests (ignore PUT, POST, DELETE, etc).
I am able to filter by text or by method:
I am not able to combine the filter to search by both text and method:
I read the documentation at https://developers.google.com/web/tools/chrome-devtools/network-performance/reference#filters and I am able to filter by multiple properties (.e.g, domain:*.com method:GET). However, I am unable to filter by text and property (e.g., method:GET chromequestion).
Unfortunately, it's not possible to do this currently. I played around in DevTools originally, but couldn't find a way. I later had a look into how the filtering was implemented, and can confirm there's a limitation preventing you from mixing the pre-defined filters and text filters.
Implementation details
This is a bit long but I thought it might be interesting for some to see how it's implemented. I will probably look into improving the implementation, either myself or I'll log it because it's limited.
There's a _parseFilterQuery function that parses the input field and categorises the entries into two arrays. The first is called filters, and it's the pre-defined filtering options, such as method:GET etc. The second is a text array filter, split up by spaces. The parser determines the difference fairly naively, by checking for the occurrence of :, and - at the start (for negation).
Scenario 1
You only input a pre-defined filter, or multiple filters. For each filter, the specific filter function, which looks at the different properties of the request object, is pushed to a network module filters array (this._filters). Later on, for each request, the function is called on it, and a match returns true, otherwise false. This will determine whether the request is shown. There's obviously a requirement for ALL filters to return true for the row to show.
Scenario 2
This is the interesting one, where you input both a pre-defined filter and a bit of text. This covers the Stack Overflow question. The _parseFilterQuery function looks at the text filters first, before the pre-defined ones. In Scenario 1, this was empty, so it was skipped.
We pass each text word to the _createTextFilter, and push each of the resulting filters to the network module filters array. However, the implementation of this is questionable. The only time the actual word passed in is used is to check whether its a negation filter for a bit of text. If the first character is -, it means the user doesn't want to see a request with the following word in the name. For example -icon means don't show any request with that in the name/page. If there is no negation, it simply returns the WHOLE input text as a regular expression, NOT the word passed in. In my case, it returns /method:GET icon/i.
The pre-defined filters are looked at next. In this case, method:GET is pushed.
Finally, it loops over the requests calling each filter on it. However, since the first filter is /method:GET icon/i, it makes ALL other filters redundant because it will NEVER pass. The text filters only apply to name and path, so method:GET in a text filter will be invalid.

Dropbox Api v2 - confusion with cursor and paging for list_folders

The files/list _folders method in api docs has the following for the description of the cursor parameter:
cursor - Pass the cursor into list_folder/continue to see what's changed in the folder since your previous query.
has_more - If true, then there are more entries available. Pass the cursor to list_folder/continue to retrieve the rest.
https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
Which is it then? If I make another request to list_folders_continue passing in the token, am I requesting another page of results or changes to the folder? If I am requesting another page of results, what is the limit that was applied? And can I control that?
The docs also have the list_folder method under sharing, which appears to have more precise definition of the cursor and the support for the limit parameter
https://www.dropbox.com/developers/documentation/http/documentation#sharing-list_folders
Will the method under files have that too?
Which is it then? If I make another request to list_folders_continue passing in the token, am I requesting another page of results or changes to the folder?
It's both. The /files/list_folder/continue endpoint is used both for returning additional pages of items, as well as getting further updates in the future.
Each page returned by /files/list_folder[/continue] is limited in size, but there is no guaranteed limit, nor can you control that limit. Your app should just always check has_more and call back to /files/list_folder/continue if it is true.
Also, the endpoints /files/list_folder and /sharing/list_folders are different endpoints with different functionality.
The /files/list_folder endpoint is documented as:
Returns the contents of a folder.
The /sharing/list_folders endpoint is documented as:
Return the list of all shared folders the current user has access to.
The two endpoints use different cursors, for use with /files/list_folder/continue and /sharing/list_folders/continue, respectively.
Which is it then? If I make another request to list_folders_continue
passing in the token, am I requesting another page of results or
changes to the folder? If I am requesting another page of results,
what is the limit that was applied? And can I control that?
My own trial and error experimentation has determined that the "It's both" answer posted by Greg is not correct. Specifically, the correct answer is "it's either". See below for more details.
When you call files/list_folder and it returns the entire list of contents (with a has_more value of false), then the cursor returned is suitable for monitoring subsequent changes to the path specified by passing that cursor to files/list_folder/continue.
If files/list_folder returns the first of multiple pages of contents (with a has_more value of true), then the cursor returned is suitable for getting the next page of contents by passing it to files/list_folder/continue. This cursor is not suitable for monitoring for changes (try it yourself, you can call continue as many times as you want with that cursor and you will always get the second page of contents).
It's not entirely clear from the docs, but when getting pages of contents from files/list_folder/continue, each call will return a new cursor, and that new cursor must be passed to a subsequent call to files/list_folder/continue in order to get the next page. You must chain the cursors together in this way until you get the last page (where has_more is false).
The cursor returned in that last call to files/list_folder/continue can then be used in subsequent calls to files/list_folder/continue to monitor for changes to the original path specified in the very first call to files/list_folder.
So the cursor is either suitable for monitoring for changes (when it is returned with a has_more value of false) OR it is suitable for getting a subsequent page of contents (when it is returned with a has_more value of true), regardless of whether the call that produced the cursor was files/list_folder or files/list_folder/continue, but it is never both.

Does the use of place parameter in queries using the Facebook Graph API affect the results of post searches?

I 've been trying to test the place parameter when used for searching post using the Facebook Graph API. However it does not seem to affect results !!
For example:
https://graph.facebook.com/search?q=coffee&type=post&center=44,55&distance=1000
in the previous URL results do not change when I change the values of latitude and longitude (44,55) or the radius (1000)
Am I doing something wrong ?
I think the "distance" and "center" parameters only work when you use the parameter "type=place".
e.g. The two links below return demonstrate this.
https://graph.facebook.com/search?q=coffee&type=place&center=44.270962,55.096039&distance=1000&access_token=[access_token]
https://graph.facebook.com/search?q=coffee&type=place&center=53.270962,-6.096039&distance=1000&access_token=[access_token]
Once you have all the places returned, you could then do a further search on each place for their posts that contain coffee...