Search code examples
azuregraphqlazure-sql-databaseazure-static-web-app

GraphQL `in` operator is not working when using Azure Static Web App


I am using Azure Static Web App with Azure SQL database. When filtering the data, I want to use the in instead of the eq operator. So far the eq operator is working as expected:

async function filterProducts() {
  const query = `
    query Products {
      products(filter: { category: { eq: "dairy" } }) {
        items {
          date
          category
          price
        }
      }
    }`;
  
  const filteredProducts = await fetch('/data-api/graphql', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query: query })
  })
    .then((response) => response.json())
    .then((dataJson) => {
      const dataItems = dataJson.data.products.items;
      const dates = dataItems.map((product) => product.date);
      const prices = dataItems.map((product) => product.price);
      return { dates, prices };
    })
    .catch((err) => console.warn('Unable to fetch from the endpoint.', err));

  return filteredProducts;
}

However, using the in operator will get a 400 status (Bad Request) error. This is the input query:

  const query = `
    query Products {
      products(filter: { category: { in: ["dairy", "fruit"] } }) {
        items {
          date
          category
          price
        }
      }
    }`;

And I got the error when calling the localhost:4280/data-api/graphql endpoint:

Failed to load resource: the server responded with a status of 400 (Bad Request)

Is it possible to use the in operator from an Azure Static Web App? How to filter multiple values using GraphQL in Azure Static Web App?


Solution

  • The https://stackoverflow.com/a/78345944/10721627 answer is incomplete because it only retrieves 100 data by default. To gather all the data, we need to use the hasNextPage as a return statement and reassign the afterCursor to the endCursor variable in each iteration.

    async function filterProducts() {
      let allProducts = [];
      let pageSize = 1000;
      let hasNextPage = true;
      let afterCursor = null;
    
      // Fetches all data from the endpoint using pagination.
      while (hasNextPage) {
        const query = `
          query Products {
            products(first: ${pageSize}, after: ${afterCursor}) {
              items {
                date
                category
                price
              }
              hasNextPage
              endCursor
            }
          }
          `;
    
        await fetch('/data-api/graphql', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ query: query })
        })
          .then((response) => response.json())
          .then((dataJson) => {
            allProducts = allProducts.concat(dataJson.data.products.items);
    
            hasNextPage = dataJson.data.products.hasNextPage;
            afterCursor = `"${dataJson.data.products.endCursor}"`;
          })
          .catch((err) => {
            console.warn('Unable to fetch the data from the `selectAllMaterialStock` endpoint.', err);
            hasNextPage = false;
          });
      }
    
      // Filters the data using the fields.
      const categories = ['dairy', 'fruits'];
      const filteredProducts = allProducts.filter((item) => categories.includes(item.category));
    
      return filteredProducts;
    }
    

    We are appending the fetched data into the allProducts array. Once we have the complete data, we can filter it with the built-in Array.prototype.filter() method since the in operator cannot be used, see the previous answer.

    Note: If there is huge data, this solution will not be the most performant alternative. A possible alternative could be to use the mssql package to directly query the database.