Expand my Community achievements bar.

SOLVED

How to extend ImageRef GraphQL models?

Avatar

Level 8

I have requirement to return more fields in ImageRef. To the standard ImageRef type 

sarav_prakash_0-1739159355021.png

I want to include, size, lastModified, createdDate, cq:tags of the asset. How to extend the ImageRef schema modal to add additional properties? 

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

1 Accepted Solution

Avatar

Correct answer by
Level 4

Hi @sarav_prakash :

You can add a filter with pattern below or if you want to implement for one query then add its complete path and filter the requests.

/graphql/execute.json.*

In the doFilter method, get the response of the query and then manipulate the response and add more fields to the response (size, lastModified, createdDate, cq:tags). Here is the sample code snippet.

@Override
public void doFilter(final ServletRequest request, final ServletResponse response,
final FilterChain filterChain) throws IOException, ServletException {
        SlingHttpServletRequest slingHttpServletRequest = (SlingHttpServletRequest) request;
//isEnabledSuffix will check for the request suffix if it contains the specific query where imageRef schema needs to be modified.
        if (isEnabledSuffix(slingHttpServletRequest.getRequestPathInfo().getSuffix())) {
            CharResponseWrapper responseWrapper = new CharResponseWrapper((HttpServletResponse) response);
            filterChain.doFilter(request, responseWrapper);

            PrintWriter responseWriter = response.getWriter();

            if (responseWriter == null) {
                return;
            }

            JsonElement jsonElement = new Gson().fromJson(responseWrapper.toString(), JsonElement.class);
            JsonObject jsonObject = jsonElement.getAsJsonObject();

            searchJson(jsonObject);//search for imageRef object in the response json

            responseWriter.write(jsonObject.toString()); //writing the modified response with more metadata back to the response
        } else {
            filterChain.doFilter(request, response);
        }
    }

private void searchJson(JsonObject jsonObject) {
        String assetUrl = StringUtils.EMPTY;

        for (Map.Entry<String, JsonElement> jsonEntry : jsonObject.entrySet()) {
            if (TYPE_NAME.equals(jsonEntry.getKey()) && IMAGE_REF.equals(jsonEntry.getValue().getAsString())) {
                assetUrl = jsonObject.get(URL).getAsString();
            }

            JsonElement jsonValue = jsonEntry.getValue();
            if (jsonValue instanceof JsonObject) {
                searchJson(jsonValue.getAsJsonObject());
            } else if (jsonValue instanceof JsonArray) {
                JsonArray jsonValues = jsonValue.getAsJsonArray();

                for (JsonElement jsonArrayValue : jsonValues) {
                    if (jsonArrayValue instanceof JsonObject) {
                        searchJson(jsonArrayValue.getAsJsonObject());
                    }
                }
            }
        }

        if (StringUtils.isNotBlank(assetUrl)) {
            setAssetMetadata(assetUrl, jsonObject); //this method gets the resource metadata and extract the properties and add those to the response json
        }
    }

Hope this helps. Let me know if you face any issues implementing this.

View solution in original post

6 Replies

Avatar

Level 5

Hi @sarav_prakash ,

 

I believe there should be a model associated with ImageRef schema and if we edit/overlay that schema and add additional fields as required. OR we can have own model created with all the required fields and reference this model in actual model where needed. We have to ensure that model should be in our project path /conf/project/....cfm/

 

Thanks,

Ramesh.

Avatar

Level 8

yup correct. Please do share if you know model or exact overlay for ootb schema type. 

Avatar

Correct answer by
Level 4

Hi @sarav_prakash :

You can add a filter with pattern below or if you want to implement for one query then add its complete path and filter the requests.

/graphql/execute.json.*

In the doFilter method, get the response of the query and then manipulate the response and add more fields to the response (size, lastModified, createdDate, cq:tags). Here is the sample code snippet.

@Override
public void doFilter(final ServletRequest request, final ServletResponse response,
final FilterChain filterChain) throws IOException, ServletException {
        SlingHttpServletRequest slingHttpServletRequest = (SlingHttpServletRequest) request;
//isEnabledSuffix will check for the request suffix if it contains the specific query where imageRef schema needs to be modified.
        if (isEnabledSuffix(slingHttpServletRequest.getRequestPathInfo().getSuffix())) {
            CharResponseWrapper responseWrapper = new CharResponseWrapper((HttpServletResponse) response);
            filterChain.doFilter(request, responseWrapper);

            PrintWriter responseWriter = response.getWriter();

            if (responseWriter == null) {
                return;
            }

            JsonElement jsonElement = new Gson().fromJson(responseWrapper.toString(), JsonElement.class);
            JsonObject jsonObject = jsonElement.getAsJsonObject();

            searchJson(jsonObject);//search for imageRef object in the response json

            responseWriter.write(jsonObject.toString()); //writing the modified response with more metadata back to the response
        } else {
            filterChain.doFilter(request, response);
        }
    }

private void searchJson(JsonObject jsonObject) {
        String assetUrl = StringUtils.EMPTY;

        for (Map.Entry<String, JsonElement> jsonEntry : jsonObject.entrySet()) {
            if (TYPE_NAME.equals(jsonEntry.getKey()) && IMAGE_REF.equals(jsonEntry.getValue().getAsString())) {
                assetUrl = jsonObject.get(URL).getAsString();
            }

            JsonElement jsonValue = jsonEntry.getValue();
            if (jsonValue instanceof JsonObject) {
                searchJson(jsonValue.getAsJsonObject());
            } else if (jsonValue instanceof JsonArray) {
                JsonArray jsonValues = jsonValue.getAsJsonArray();

                for (JsonElement jsonArrayValue : jsonValues) {
                    if (jsonArrayValue instanceof JsonObject) {
                        searchJson(jsonArrayValue.getAsJsonObject());
                    }
                }
            }
        }

        if (StringUtils.isNotBlank(assetUrl)) {
            setAssetMetadata(assetUrl, jsonObject); //this method gets the resource metadata and extract the properties and add those to the response json
        }
    }

Hope this helps. Let me know if you face any issues implementing this.

Avatar

Level 8

got it. agreed filter can intercept response and we can add custom transform logic. I was looking specifically for custom schema type. So instead of ImageRef, if we could create custom type, it can be reused in multiple queries. 

 

FE is running different queries, and they need different extra asset properties. Above, for each query, I need to write custom transformer filter. Instead if there is way to extend ImageRef type and create custom type, will be better. 

 

Are you aware of such approach? 

Avatar

Community Advisor

Hi @sarav_prakash ,

ImageRef type provides basic properties of the referenced image but does not include detailed metadata like jcr:created, jcr:lastModified, or cq:tags. Additionally, the _metadata field is designed to expose metadata of the Content Fragment itself, not the assets it references.

query homePageMain($path: String!, $variation: String) {
  homePageByPath(_path: $path, variation: $variation) {
    item {
      _metadata {
        stringMetadata {
          name
          value
        }
        dateMetadata {
          name
          value
        }
        longMetadata {
          name
          value
        }
        stringArrayMetadata {
          name
          values
        }
      }
      imageField {
        ... on ImageRef {
          _path
          title
          description
          width
          height
          mimeType
        }
      }
    }
  }
}

To get the custom metadata fields for Image Reference, You can follow any of the below approach.

First approach :

You can create a new content fragment model which have fields for Image path along with custom metadata fields, which we can configure manually or create a listener to update value automatically.

Second approach :

You can use Sling filters to update the response which have data of custom metadata as explain by @AshwiniSathe1 .

Reference : https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/headless/graphql...

Regards, 

Shiv Prakash

First approach: Content duplication. Big no. I have a million assets. Technically its bad to duplicate housekeeping properties like lastModified, createdDate etc. 

 

Second approach: Yes technically this ll work. I can also do a RequestDispatcher with a custom SlingHttpServletResponseWrapper. But was looking for a way to extend ootb type to include required custom properties.So FE can design graphql and pick properties as required.