AppEngine Integration

Complete guide to integrating AppEngine Service with your Next.js application

Quick Overview

AppEngine is a powerful backend API service hosted at appengine.appmint.io that handles data management, authentication, and API operations. This integration uses a proxy pattern to securely connect your Next.js application with AppEngine services without exposing credentials to the client.

Secure Proxy

API calls route through Next.js server

Dual Auth

API Key or Dynamic Token support

Auto Token

Client library handles tokens

Architecture Overview

1

Client Browser

Makes requests to /api/[...slug] endpoint

2

Next.js API Route (Proxy)

Intercepts requests, adds authentication, forwards to AppEngine

3

AppEngine Service (appengine.appmint.io)

Processes request with proper authentication and returns data

Why use a proxy? The proxy pattern prevents exposing AppEngine credentials to the client browser, ensuring all sensitive API keys and tokens remain secure on the server side.

Step 1: Environment Configuration

Configure your environment variables to connect with AppEngine. You have two authentication options:

Option A: API Key Authentication

Create an API key in the AppEngine dashboard at appengine.appmint.io and add it to your environment:

.env.local
# AppEngine Configuration with API Key
APPENGINE_ENDPOINT=https://appengine.appmint.io
APPENGINE_API_KEY=your_api_key_here
ORG_ID=your_organization_id
SITE_NAME=your_site_name
SITE_URL=https://yourdomain.com

Option B: App User Credentials (Recommended)

Create an App User in the AppEngine dashboard at appengine.appmint.io. The AppEngine client library will automatically handle token generation and renewal using these credentials:

.env.local
# AppEngine Configuration with App Credentials
APPENGINE_ENDPOINT=https://appengine.appmint.io
APP_ID=your_app_id
APP_KEY=your_app_key
APP_SECRET=your_app_secret
ORG_ID=your_organization_id
SITE_NAME=your_site_name
SITE_URL=https://yourdomain.com

# Optional configurations
DOMAIN_AS_ORG=false
DEFAULT_LOCALE=en
DEFAULT_TITLE=Your App Title
DEFAULT_DESCRIPTION=Your app description
MAX_ATTACHMENT_SIZE=10485760

Automatic Token Management: When using app credentials, the AppEngine client automatically handles token generation and renewal. You don't need to manually manage tokens.

Step 2: Proxy Route Setup

The proxy route handles all API requests from your client and forwards them to AppEngine with proper authentication.

src/app/api/[...slug]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getAppEngineClient } from '@/lib/appmint-client';

export async function GET(request: NextRequest, { params }: { params: Promise<{ slug: string[] }> }) {
  return handleRequest('GET', request, await params);
}

export async function POST(request: NextRequest, { params }: { params: Promise<{ slug: string[] }> }) {
  return handleRequest('POST', request, await params);
}

export async function PUT(request: NextRequest, { params }: { params: Promise<{ slug: string[] }> }) {
  return handleRequest('PUT', request, await params);
}

export async function DELETE(request: NextRequest, { params }: { params: Promise<{ slug: string[] }> }) {
  return handleRequest('DELETE', request, await params);
}

async function handleRequest(method: string, request: NextRequest, params: { slug: string[] }) {
  try {
    // Get the path from the slug parameters
    const clientPath = params.slug.join('/');

    // Get query parameters
    const url = new URL(request.url);
    const clientQuery = Object.fromEntries(url.searchParams.entries());

    // Get request body for POST/PUT/PATCH requests
    let clientData = null;
    if (['POST', 'PUT', 'PATCH'].includes(method)) {
      const contentType = request.headers.get('content-type');
      if (contentType?.includes('application/json')) {
        clientData = await request.json();
      } else if (contentType?.includes('multipart/form-data')) {
        clientData = await request.formData();
      } else {
        clientData = await request.text();
      }
    }

    // Get authorization from header or cookie
    let clientAuthorization = request.headers.get('authorization');
    if (!clientAuthorization) {
      const token = request.cookies.get('token');
      if (token) {
        clientAuthorization = `Bearer ${token.value}`;
      }
    }

    // Process the request using AppEngineClient
    const appEngineClient = getAppEngineClient();
    const result = await appEngineClient.processRequest(
      method,
      clientPath,
      clientData,
      clientAuthorization,
      clientQuery
    );

    return NextResponse.json(result);
  } catch (error) {
    console.error('API Route Error:', error);
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    );
  }
}

Important: The catch-all route [...slug] captures all paths after/api/ and forwards them to AppEngine, maintaining the same URL structure.

Step 3: AppEngine Client Library

The AppEngine client library handles authentication, token management, and request processing.

Configuration File

src/lib/appmint-config.ts
const appmintConfig = {
  useAppEngine: true,
  appengine: {
    host: process.env.APPENGINE_ENDPOINT,
    appId: process.env.APP_ID,
    key: process.env.APP_KEY,
    secret: process.env.APP_SECRET,
    apiKey: process.env.APPENGINE_API_KEY,
  },
  siteURL: process.env.SITE_URL,
  orgId: process.env.ORG_ID,
  siteName: process.env.SITE_NAME,
  domainAsOrg: process.env.DOMAIN_AS_ORG,
};

export { appmintConfig };

Client Implementation

src/lib/appmint-client.ts
import { appmintConfig } from './appmint-config';
import axios from 'axios';

export class AppEngineClient {
  private token: string | null = null;

  constructor(private appConfig: any) {}

  // Automatically get app token using credentials
  async getAppToken() {
    const data = {
      appId: this.appConfig.appengine.appId,
      secret: this.appConfig.appengine.secret,
      key: this.appConfig.appengine.key,
    };

    // Calls profile/app/key endpoint to get token
    const response = await axios.post(
      `${this.appConfig.appengine.host}/profile/app/key`,
      data
    );
    return response.data.token;
  }

  // Get headers with authentication
  async getHeaderWithToken() {
    if (!this.token) {
      this.token = await this.getAppToken();
    }

    return {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.token}`,
        'x-api-key': this.appConfig.appengine.apiKey,
        'org-id': this.appConfig.orgId,
      }
    };
  }

  // Process requests with automatic token renewal
  async processRequest(method: string, path: string, data?: any) {
    try {
      const headers = await this.getHeaderWithToken();
      const response = await axios({
        method,
        url: path,
        data,
        ...headers
      });

      return response.data;
    } catch (error: any) {
      // Auto-renew token if expired
      if (error?.response?.status === 401) {
        this.token = null;
        return this.processRequest(method, path, data);
      }
      throw error;
    }
  }
}

// Singleton instance
let appEngineClient: AppEngineClient;

export const getAppEngineClient = (): AppEngineClient => {
  if (!appEngineClient) {
    appEngineClient = new AppEngineClient(appmintConfig);
  }
  return appEngineClient;
};

Step 4: Using the AppEngine Client

Here are examples of how to use the AppEngine client in your application:

Server-Side Usage

Server Component or API Route
import { getAppEngineClient } from '@/lib/appmint-client';

// Get the client instance
const appEngineClient = getAppEngineClient();

// Fetch data
const users = await appEngineClient.processRequest('GET', '/users');

// Create data
const newUser = await appEngineClient.processRequest('POST', '/users', {
  name: 'John Doe',
  email: 'john@example.com'
});

// Update data
const updatedUser = await appEngineClient.processRequest('PUT', '/users/123', {
  name: 'Jane Doe'
});

// Delete data
await appEngineClient.processRequest('DELETE', '/users/123');

// Use built-in repository methods
const userData = await appEngineClient.getById('users', '123');
const searchResults = await appEngineClient.findData('users', { name: 'john' });
const aggregated = await appEngineClient.processRequest('POST', '/repository/aggregate', data);

Client-Side Usage

React Component
import { useState, useEffect } from 'react';

export function UserList() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    // Client-side requests go through the proxy
    fetch('/api/users')
      .then(res => res.json())
      .then(data => setUsers(data));
  }, []);

  const createUser = async (userData) => {
    const response = await fetch('/api/users', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${getToken()}` // Optional: if using user tokens
      },
      body: JSON.stringify(userData)
    });

    return response.json();
  };

  return (
    <div>
      {users.map(user => (
        <div key={user.id}>{user.name}</div>
      ))}
    </div>
  );
}

Key AppEngine Endpoints

AppEngine provides a comprehensive set of API endpoints. Here are the most commonly used ones:

Repository Operations

  • • repository/get - Get data by ID
  • • repository/create - Create new records
  • • repository/update - Update existing records
  • • repository/delete - Delete records
  • • repository/find - Find records by query
  • • repository/search - Search with keywords
  • • repository/aggregate - Aggregate operations

Authentication & Profile

  • • profile/app/key - Get app token with credentials
  • • profile/customer/signin - User sign in
  • • profile/customer/signup - User registration
  • • profile/customer/profile - Get user profile
  • • profile/customer/refresh - Refresh token

CRM Operations

  • • crm/leads - Lead management
  • • crm/tickets/create - Create support tickets
  • • crm/contact-form/json - Submit contact forms
  • • crm/marketing/campaigns - Marketing campaigns
  • • crm/events/get - Event management

AI & Tools

  • • ai/generate - AI content generation
  • • ai/agent/process - AI agent processing
  • • ai/assistants/run - Run AI assistants
  • • tools/remove-background - Image processing

Full API Reference: For a complete list of available endpoints, refer to the AppEngine API documentation at appengine.appmint.io or check the appmint-endpoints.ts file in your project.

Authentication Methods

1. API Key Authentication

Best for server-to-server communication and backend services.

  • Create API key in AppEngine dashboard (appengine.appmint.io)
  • Set as APPENGINE_API_KEY environment variable
  • Client automatically includes in requests

2. Dynamic Token Authentication

Best for user-specific operations and client applications.

  • User authenticates and receives token
  • Token passed in Authorization header
  • Proxy forwards token to AppEngine

3. App User Credentials

Best for automated services and backend integrations.

  • Create App User in AppEngine dashboard (appengine.appmint.io)
  • Set APP_ID, APP_KEY, APP_SECRET
  • Client auto-generates and renews tokens

Best Practices

1

Never expose credentials

Keep all API keys and secrets in environment variables, never commit them to version control.

2

Use the proxy pattern

Always route client requests through the Next.js API proxy to keep credentials server-side.

3

Implement error handling

Add proper error handling and logging to track and debug issues effectively.

4

Cache when appropriate

Implement caching strategies to reduce API calls and improve performance.

5

Monitor token expiration

The client library handles token renewal automatically, but monitor for authentication issues.

Troubleshooting

401 Unauthorized Errors

  • • Check API key or credentials are correctly set in environment variables
  • • Verify the AppEngine service is accessible from your server
  • • Ensure tokens haven't expired (client should auto-renew)

CORS Issues

  • • Client should call your Next.js API routes, not AppEngine directly
  • • Ensure proxy route is correctly configured at /api/[...slug]
  • • Check that client requests use relative URLs (e.g., /api/users)

Connection Errors

  • • Verify APPENGINE_ENDPOINT is correct and accessible
  • • Check network connectivity from your server
  • • Review firewall rules if running in production

Next Steps