Skip to content
Juliet Shin edited this page May 16, 2025 · 12 revisions

Table of Contents

Introduction

The dmsp_frontend_app is a web application built using NextJS React framework and TypeScript. The app serves up all the pages for the DMP Tool, and uses Apollo GraphQL Client to make requests to the backend server.

This app was bootstrapped with create-next-app.

The app is a hybrid framework using both frontend and backend logic. The app includes one API endpoints for checking auth state. It also uses middleware to check for tokens and to handle routing for localization.

Graphql

The app uses Apollo Client to make requests to the backend Apollo Server. The app uses an ApolloWrapper, which is located at lib/graphql/apollo-wrapper.tsx to implement Apollo Client on the pages.

The app is using graphql-codegen to generate types from graphql queries and mutations. Please place your queries in the graphql directory and name the file like graphql/<name>.<query|mutation>.graphql per the codegen.ts config file. This will generate the generated/graphql.tsx file, and you can use the generated functions or documents to make the graphql requests.

Once the schema has been added, you will need to run npm run generate this kicks off a script that builds out Typescript Types for the new schema and queries. The schema is dependent on the graphql server running at dmsp_backend_prototype in order to successfully generate.

Using the generated files in your component

There are many options available to you from the generated graphql.tsx file. For example, in addition to the basic query function, you have the option to use lazy queries, suspense queries, and also access the actual gql document.

Examples of usage:

import {
  useMeQuery,
} from '@/generated/graphql';

  const { data, loading: queryLoading, error: queryError, refetch } = useMeQuery();

import { useAffiliationsLazyQuery } from '@/generated/graphql' // adjust the path as needed

export default function AffiliationSearch() {
  const [searchTerm, setSearchTerm] = useState('')
  const [fetchAffiliations, { data, loading, error, called }] = useAffiliationsLazyQuery()

  const handleSearch = () => {
    if (searchTerm.trim() !== '') {
      fetchAffiliations({ variables: { term: searchTerm } }) // assuming your query takes a `term` variable
    }
  }

import { UpdateTemplateDocument, TemplateVisibility } from "@/generated/graphql";

  try {
    // Execute the mutation using the shared handler
    return executeGraphQLMutation({
      document: UpdateTemplateDocument,
      variables: { templateId, name, visibility },
      dataPath: "updateTemplate"
    });

  } catch (error) {
    logger.error(`[Update Template Error]: ${error}`, { error });
    return { success: false, errors: ["There was a problem connecting to the server. Please try again."] };
  }

AWS CodeBuild

We use AWS CodeBuild to build our app in the pipeline. It uses a set of build commands in the file buildspec.yaml located at the root of the app.

Backend APIs

Outside of GraphQL requests, the app uses two API endpoints to sign up and log in users.

  • process.env.NEXT_PUBLIC_SERVER_ENDPOINT}/signin
  • process.env.NEXT_PUBLIC_SERVER_ENDPOINT}/signup

Authentication

We use a CsrfProvider to set the csrfToken which is returned from the backend in a response header X-CSRF-TOKEN. This token needs to be passed back in the header when logging in or signing up or refreshing auth tokens.

When a user logs in or signs up, the backend server adds auth token cookies to the client's browser: dmspr (refresh token) and dmspt (auth token). The auth token is intermittently refreshed if the refresh token is valid.