Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid loading attribute mutators when using sparse fieldset #241

Open
freestyledork opened this issue May 2, 2023 · 3 comments
Open

Avoid loading attribute mutators when using sparse fieldset #241

freestyledork opened this issue May 2, 2023 · 3 comments

Comments

@freestyledork
Copy link

I know the current version only filters the output for sparse fields. I was wondering if there is an easy fix to avoid loading mutator attributes. I have a few attributes on my models with some complex logic that are getting ran every request when it's not needed resulting in a lot of extra database hits and performance slowdowns. I've tried messing with eager loads, but that gets messy quick. I am open to other solutions, perhaps proxy models? I would prefer keep the calls clean if at all possible.

Any advice is appreciated.
Thanks

@freestyledork
Copy link
Author

I attempted to come up with a temporary solution for not loading sparse fields. Extending the JsonApiResource and using custom resource classes I can effectively avoid loading unrelated fields. This hasn't been tested in all scenarios. I am not sure if it will work in all combination of available options, but for my initial needs, it's sufficient. Perhaps a head start of some logic needed for v4.

Create a JsonApiResource class extending the package base class to add a couple helper methods.

    /**
     * Extract sparse field sets from the provided request.
     *
     * @param  Request  $request
     *
     * @return FieldSets|null
     */
    protected function extractSparseFieldSets($request): ?FieldSets
    {
        if ($request instanceof QueryParameters) {
            return $request->sparseFieldSets();
        }

        if ($request->query->has('fields')) {
            return FieldSets::fromArray($request->query('fields') ?: []);
        }

        return null;
    }

    protected function getDefaultAttributes($request): array
    {
        $sparseFields      = $this->extractSparseFieldSets($request);
        $fields            = $sparseFields?->fields()[$this->type] ?? [];
        $usingSparseFields = count($fields) > 0;

        $schemaAttributes = [];
        foreach ($this->schema->attributes() as $attr) {
            if ($attr instanceof SerializableAttribute && $attr->isNotHidden($request)) {
                $fieldName = $attr->serializedFieldName();
                if ( ! $usingSparseFields || in_array($fieldName, $fields, true)) {
                    $schemaAttributes[$fieldName] = $attr->serialize($this->resource);
                }
            }
        }

        return $schemaAttributes;
    }

Then from every custom models resource class I just call the $this-getDefaultAttributes($request) from the attributes function.

@lindyhopchris Do you see any obvious issues with this solution?

@lindyhopchris
Copy link
Contributor

Hey! Sorry for not replying to this earlier. I see no problem with that as a temporary solution. I'm planning a permanent solution for the sparse fieldsets as part of all the upgrades I'm working on at the moment.

@Tito1337
Copy link

Tito1337 commented Sep 2, 2024

Hello @lindyhopchris, is this still being worked on? I don't see any mention of it on your "Big Board of Everything" at https://github.com/orgs/laravel-json-api/projects/1

Thanks for all your work !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants