3

Flatten Strapi 4's response JSON · GitHub

 1 year ago
source link: https://gist.github.com/hucancode/5b495aabf75fc3b940df3e5f94d5b927
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Flatten Strapi 4's response JSON · GitHub

Graphql Support [Partially tested!!!]

// src/middlewares/flatten-response.js

const fs = require("fs");

const normalize = (data) => {
  const isObject = (data) =>
    Object.prototype.toString.call(data) === "[object Object]";
  const isArray = (data) =>
    Object.prototype.toString.call(data) === "[object Array]";

  const flatten = (data) => {
    if (!data.attributes) return data;

    return {
      id: data.id,
      ...data.attributes,
    };
  };

  if (isArray(data)) {
    return data.map((item) => normalize(item));
  }

  if (isObject(data)) {
    if (isArray(data.data)) {
      data = [...data.data];
    } else if (isObject(data.data)) {
      data = flatten({ ...data.data });
    } else if (data.data === null) {
      data = null;
    } else {
      data = flatten(data);
    }

    for (const key in data) {
      data[key] = normalize(data[key]);
    }

    return data;
  }

  return data;
};

const fixTypeDefName = (name) => {
  name = name.replace("RelationResponseCollection", "s");
  name = name.replace("EntityResponseCollection", "s");
  name = name.replace("EntityResponse", "");
  name = name.replace("Entity", "");

  return name;
};

const fixTypeRefName = (typeDef) => {
  if (
    typeDef.name != null &&
    typeDef.name.endsWith("EntityResponseCollection")
  ) {
    typeDef.ofType = {
      kind: "NON_NULL",
      name: null,
      ofType: {
        kind: "OBJECT",
        name: typeDef.name.replace("EntityResponseCollection", ""),
        ofType: null,
      },
    };
    typeDef.kind = "LIST";
    typeDef.name = null;

    return typeDef;
  }

  if (typeDef.ofType != null) {
    typeDef.ofType = fixTypeRefName(typeDef.ofType);
  }

  if (typeDef.name != null) {
    typeDef.name = fixTypeDefName(typeDef.name);
  }

  return typeDef;
};

const fixTypeDef = (typeDef) => {
  const fixedType = {
    ...typeDef,
    name: fixTypeDefName(typeDef.name),
  };

  fixedType.fields = typeDef.fields.map((y) => ({
    ...y,
    type: {
      ...fixTypeRefName(y.type),
    },
  }));

  return fixedType;
};

const respond = async (ctx, next) => {
  await next();

  // REST API response
  if (ctx.url.startsWith("/api")) {
    console.log(
      `API request (${ctx.url}) detected, transforming response json...`
    );
    ctx.response.body = {
      ...ctx.response.body,
      data: normalize(ctx.response.body.data),
    };
    return;
  }

  // GraphQL Response for Apollo Codegen script
  if (
    ctx.url.startsWith("/graphql") &&
    ctx.request.headers.apollocodegen === "true"
  ) {
    const parsedBody = JSON.parse(ctx.response.body);
    parsedBody.data.__schema.types = parsedBody.data.__schema.types
      .filter((x) => !x.name.endsWith("Entity"))
      .filter((x) => !x.name.endsWith("EntityResponse"))
      .filter((x) => !x.name.endsWith("EntityResponseCollection"))
      .map((x) => {
        if (x.fields == null) return x;
        if (x.name == null) return x;

        if (x.name === "Query" || x.name === "Mutation") {
          return {
            ...x,
            fields: x.fields.map((y) => ({
              ...y,
              type: {
                ...fixTypeRefName(y.type),
              },
            })),
          };
        }

        return fixTypeDef(x);
      });

    // Uncomment to Debug: Dump parsedBody to a file
    // fs.writeFileSync("./schema.json", JSON.stringify(parsedBody, null, 2));

    ctx.response.body = parsedBody;
    return;
  }

  // GraphQL Response for Apollo Client
  if (
    ctx.url.startsWith("/graphql") &&
    ctx.request.headers.normalize === "true"
  ) {
    const parsedBody = JSON.parse(ctx.response.body);

    if (parsedBody.data.__schema !== undefined) {
      return;
    }

    console.log(
      `API request (${ctx.url}) detected, transforming response json...`
    );

    ctx.response.body = {
      ...parsedBody.data,
      data: normalize(parsedBody.data),
    };
    return;
  }
};

module.exports = () => respond;

Apollo Codegen command

yarn apollo codegen:generate --target=typescript --tagName=gql --includes='operations/**/types.ts' --endpoint=http://localhost:1337/graphql --header='apollocodegen: true'

Folder Structure for queries:
image

index.ts should contain the real query

import { gql } from '@apollo/client';

export const GET_ASSETS_QUERY = gql`
  query GetAssetsQuery {
    asset {
      data {
        attributes {
          banner {
            data {
              attributes {
                url
              }
            }
          }
          logo {
            data {
              attributes {
                url
              }
            }
          }
        }
      }
    }
  }
`;

export * from './__generated__/GetAssetsQuery';

types.ts the response type

import { gql } from '@apollo/client';

export const GET_ASSETS_QUERY = gql`
  query GetAssetsQuery {
    asset {
      banner {
        url
      }
      logo {
        url
      }
    }
  }
`;

Final result is this :

image

And the return types will be generated correctly in your typescript code


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK