I have collection for doctors, they include many different fields, some of which a big in size. So when I run query to fetch them all, response size becomes scary.
However, logic that uses it only requires few small fields, leaving most of response data unused. Is it possible to transform query to get those few fields instead of whole document in rest api?
I want to avoid using graphql because running gql client on ssr/ssg frontend is too complex, and contents of queries are only changed manually in code, if at all
The problem is actually a little deeper, as each document pulls another related collection. And also one more collection, which in turn pulls that second collection
The rest api exposes a depth query parameter. That controls how many levels of related documents should be retrieved. Maybe that'll work in your case?
I thought about it. It can decrease size to certain degree, but still far from what selective query would achieve
You might have to go the custom endpoints route where you'll be able to make your own graphql queries.
Either that or do some pre-processing and cleanup using the
beforeRead
hook.
How would I proceed with custom endpoints if I only need id and slug from related collections?
I unfortunately won't be able to help much here as I haven't yet had the opportunity to play with either custom endpoints or graphql queries, but the docs would be a good place to start. 😊
https://payloadcms.com/docs/rest-api/overview#custom-endpointsI have done something along these lines, it would look a little somthing like:
{
path: '/my-endpoint',
method: 'get',
handler: async (req, res) => {
const queryResult = await payload.find({
collection: 'collection-name',
limit: 0, // 0 gets all
});
if (queryResult.docs.length === 0) {
res.status(404).json({ message: 'Nothing found' });
return;
}
const cleanedDocs = queryResult.docs.map((doc) => {
// Do something with each doc, like getting only the properties you need
return {
property1: doc.property1,
property2: doc.property2,
};
});
res.status(200).json({
...queryResult,
docs: cleanedDocs,
});
}
}
That looks good, I will try it
You can also use authentication for this. If a certain type of user never needs to see these fields, You just don't give them read access to those fields.
If you do go for the custom endpoint, you don't need to use that
limit: 0
thing, but instead you can just pass the pagination query parameters on to the find function.
I need that limit 0. If I could paginate, response size would not be much problem, probably
I found one problem with custom endpoints. They pull drafts when they are not supposed to. My access setting only allows getting published documents from api, yet custom endpoint pulls drafts. I also specified
draft: false
in .find options, but still get drafts.
That's odd! Do you mind sharing your code / query? 👀
filtering for _status serves drafts too
const queryResult = await payload.find({
collection: 'doctors',
limit: 0,
where: {
['_status']: { equals: 'published' },
},
})
Are you sure about that
['_status']
syntax (vs just
'_status':
)? 🤔
Probably. It is normal styntax for objects
object['some strange property name']
Oh okay, I wasn't familiar with that syntax within an object definition. 👍
It's pretty odd either way though. According to the docs:
If you simply fetch your created document using afind
orfindByID
operation, your published document will be returned and the drafts will be ignored.
So by default, a simple
.find()
should not return drafts unless
draft: true
is specified. Weird... 🤔
And you're 100% sure that it's actually returning drafts, right? Like the docs returned have the
_status: draft
property?
Yes. I added js filter just before mapping array and only included published, with this everything works, but with previous attempts frontend build failed exactly because this query returns drafts and default endpoint fails to fetch this draft
Hi @arctomachine , I've written a plugin called [payload-query](
https://www.npmjs.com/package/payload-query) that provides you with exactly what you're looking for.
It includes a simple plugin that adds the ability to pass a
select
query parameter into any Payload rest endpoint.
You can use it like this:
http://localhost:3000/api/posts?select[color]=true
You can also use it to omit some fields instead of selecting, if that's more convenient.
this is because local api bypasses access control by default
you can opt back into access control being enabled / functioning normally via
overrideAccess: false
in any local api operation
also worth noting for everyone else in this thread, a
select
arg has been asked for quite a bit, and we have been hesitant to implement it due to the fact that graphql supports this / is purpose-built for this reason, but we have been getting such consistent questions about this feature that we are now thinking we should probably support it
there is a PR open that gets us most of the way there
I tried this option and got even more strange results. Even if request sends correct api token, console gives forbidden error, then dev server crashes.
Hey @arctomachine how are you getting on here? do you still need help?
I solved it with custom endpoints. Not optimal, but it works. But if there was better way introduced in meantime, I will look into it too
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.