> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Antony-Figueroa/my-evershop-app/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating API Endpoints

> Learn how to create RESTful API endpoints in EverShop

API endpoints allow you to create custom RESTful routes for your EverShop store. They're perfect for handling form submissions, webhooks, integrations, and custom business logic.

## Overview

EverShop uses a file-based routing system where:

* **Directory name** = endpoint path
* **route.json** = route configuration (methods, access)
* **Middleware files** = request handlers with execution order

## Directory Structure

API endpoints are created in the `api` folder of your extension:

```
extensions/[extension-name]/
└── src/
    └── api/
        └── [endpoint-name]/
            ├── route.json                    # Route configuration
            ├── [middleware1]handler.ts       # Middleware with order
            └── middleware1.ts                # Middleware function
```

## Creating Your First API Endpoint

<Steps>
  ### Create the Endpoint Directory

  Create a directory for your endpoint:

  ```bash theme={null}
  mkdir -p extensions/my-extension/src/api/createFoo
  ```

  The directory name determines the route path. For example, `createFoo` would be accessible at `/foos`.

  ### Create route.json

  Define the route configuration:

  ```json title="src/api/createFoo/route.json" theme={null}
  {
    "methods": ["POST"],
    "path": "/foos",
    "access": "private"
  }
  ```

  <Note>
    **Access Levels:**

    * `public` - Accessible to everyone
    * `private` - Requires authentication
  </Note>

  ### Create Middleware

  Create a body parser middleware:

  ```typescript title="src/api/createFoo/bodyParser.ts" theme={null}
  import bodyParser from 'body-parser';

  export default (request, response, next) => {
    bodyParser.json({ inflate: false })(request, response, next);
  };
  ```

  ### Create the Handler

  Create the main handler with middleware ordering:

  ```typescript title="src/api/createFoo/[bodyParser]createFoo.ts" theme={null}
  import { EvershopRequest, EvershopResponse } from '@evershop/evershop';

  export default (request: EvershopRequest, response: EvershopResponse, next) => {
    const { name, description } = request.body;

    if (!name || !description) {
      return response
        .status(400)
        .json({ error: 'Name and description are required' });
    }

    // Create the new foo item
    const newFoo = {
      id: Date.now(),
      name,
      description
    };

    // Simulate saving to a database
    console.log('Creating new foo:', newFoo);

    // Respond with the created foo item
    response.status(201).json({
      success: true,
      data: {
        foo: newFoo
      }
    });
  };
  ```

  <Warning>
    The `[bodyParser]` prefix ensures the body parser runs before the handler. This is the middleware execution order.
  </Warning>
</Steps>

## Middleware Execution Order

Middleware execution is controlled by filename prefixes in square brackets:

```
[middleware1]handler.ts      # Runs after middleware1
[middleware1][middleware2]handler.ts  # Runs after both
```

### Example Middleware Chain

```
src/api/createProduct/
├── route.json
├── authenticate.ts
├── [authenticate]validateInput.ts
└── [authenticate][validateInput]createProduct.ts
```

Execution order:

1. `authenticate.ts`
2. `validateInput.ts`
3. `createProduct.ts`

## Route Configuration

### HTTP Methods

Specify which HTTP methods are allowed:

```json theme={null}
{
  "methods": ["GET", "POST", "PUT", "DELETE"],
  "path": "/api/items",
  "access": "public"
}
```

### Custom Paths

Override the default path:

```json theme={null}
{
  "methods": ["POST"],
  "path": "/api/v2/custom/endpoint",
  "access": "private"
}
```

### Dynamic Parameters

Use URL parameters:

```json theme={null}
{
  "methods": ["GET"],
  "path": "/api/items/:id",
  "access": "public"
}
```

Access in handler:

```typescript theme={null}
export default (request, response) => {
  const { id } = request.params;
  // ...
};
```

## Real-World Examples

### GET Endpoint

Fetch data from the database:

```typescript title="src/api/getFoos/getFoos.ts" theme={null}
import { EvershopRequest, EvershopResponse } from '@evershop/evershop';

export default async (request: EvershopRequest, response: EvershopResponse) => {
  try {
    // Fetch from database (example)
    const foos = [
      { id: 1, name: 'Foo', description: 'This is a Foo object' },
      { id: 2, name: 'Bar', description: 'This is a Bar object' }
    ];

    response.json({
      success: true,
      data: { foos }
    });
  } catch (error) {
    response.status(500).json({
      success: false,
      error: 'Failed to fetch foos'
    });
  }
};
```

```json title="src/api/getFoos/route.json" theme={null}
{
  "methods": ["GET"],
  "path": "/foos",
  "access": "public"
}
```

### POST with Validation

Create a resource with input validation:

```typescript title="src/api/createFoo/validateInput.ts" theme={null}
import { EvershopRequest, EvershopResponse } from '@evershop/evershop';

export default (request: EvershopRequest, response: EvershopResponse, next) => {
  const { name, description } = request.body;

  const errors = [];

  if (!name || name.trim().length === 0) {
    errors.push({ field: 'name', message: 'Name is required' });
  }

  if (!description || description.trim().length < 10) {
    errors.push({ 
      field: 'description', 
      message: 'Description must be at least 10 characters' 
    });
  }

  if (errors.length > 0) {
    return response.status(400).json({
      success: false,
      errors
    });
  }

  next();
};
```

```typescript title="src/api/createFoo/[bodyParser][validateInput]createFoo.ts" theme={null}
import { EvershopRequest, EvershopResponse } from '@evershop/evershop';

export default async (request: EvershopRequest, response: EvershopResponse) => {
  try {
    const { name, description } = request.body;

    // Save to database (example)
    const newFoo = {
      id: Date.now(),
      name,
      description,
      createdAt: new Date().toISOString()
    };

    response.status(201).json({
      success: true,
      data: { foo: newFoo }
    });
  } catch (error) {
    response.status(500).json({
      success: false,
      error: 'Failed to create foo'
    });
  }
};
```

### PUT/PATCH Endpoint

Update a resource:

```typescript title="src/api/updateFoo/[bodyParser]updateFoo.ts" theme={null}
import { EvershopRequest, EvershopResponse } from '@evershop/evershop';

export default async (request: EvershopRequest, response: EvershopResponse) => {
  try {
    const { id } = request.params;
    const { name, description } = request.body;

    // Update in database (example)
    const updatedFoo = {
      id: parseInt(id),
      name,
      description,
      updatedAt: new Date().toISOString()
    };

    response.json({
      success: true,
      data: { foo: updatedFoo }
    });
  } catch (error) {
    response.status(500).json({
      success: false,
      error: 'Failed to update foo'
    });
  }
};
```

```json title="src/api/updateFoo/route.json" theme={null}
{
  "methods": ["PUT", "PATCH"],
  "path": "/foos/:id",
  "access": "private"
}
```

### DELETE Endpoint

Delete a resource:

```typescript title="src/api/deleteFoo/deleteFoo.ts" theme={null}
import { EvershopRequest, EvershopResponse } from '@evershop/evershop';

export default async (request: EvershopRequest, response: EvershopResponse) => {
  try {
    const { id } = request.params;

    // Delete from database (example)
    console.log(`Deleting foo with id: ${id}`);

    response.json({
      success: true,
      message: 'Foo deleted successfully'
    });
  } catch (error) {
    response.status(500).json({
      success: false,
      error: 'Failed to delete foo'
    });
  }
};
```

```json title="src/api/deleteFoo/route.json" theme={null}
{
  "methods": ["DELETE"],
  "path": "/foos/:id",
  "access": "private"
}
```

## Authentication & Authorization

### Private Endpoints

Endpoints with `"access": "private"` require authentication:

```json theme={null}
{
  "methods": ["POST"],
  "path": "/api/admin/action",
  "access": "private"
}
```

### Custom Authentication

Create an authentication middleware:

```typescript title="src/api/protected/authenticate.ts" theme={null}
import { EvershopRequest, EvershopResponse } from '@evershop/evershop';

export default (request: EvershopRequest, response: EvershopResponse, next) => {
  const token = request.headers.authorization?.replace('Bearer ', '');

  if (!token) {
    return response.status(401).json({
      success: false,
      error: 'Authentication required'
    });
  }

  // Verify token (example)
  try {
    // Validate token logic here
    request.user = { id: 1, email: 'user@example.com' };
    next();
  } catch (error) {
    return response.status(401).json({
      success: false,
      error: 'Invalid token'
    });
  }
};
```

## Error Handling

### Standard Error Response

```typescript theme={null}
try {
  // Your logic
} catch (error) {
  console.error('Error:', error);
  response.status(500).json({
    success: false,
    error: 'An unexpected error occurred'
  });
}
```

### Validation Errors

```typescript theme={null}
const errors = [];

if (!email || !email.includes('@')) {
  errors.push({ field: 'email', message: 'Valid email is required' });
}

if (errors.length > 0) {
  return response.status(400).json({
    success: false,
    errors
  });
}
```

## Testing API Endpoints

### Using cURL

```bash theme={null}
# GET request
curl http://localhost:3000/foos

# POST request
curl -X POST http://localhost:3000/foos \
  -H "Content-Type: application/json" \
  -d '{"name":"New Foo","description":"A new foo item"}'

# PUT request
curl -X PUT http://localhost:3000/foos/123 \
  -H "Content-Type: application/json" \
  -d '{"name":"Updated Foo","description":"Updated description"}'

# DELETE request
curl -X DELETE http://localhost:3000/foos/123
```

### Using Postman

1. Create a new request
2. Set the method (GET, POST, PUT, DELETE)
3. Enter the URL: `http://localhost:3000/foos`
4. Add headers: `Content-Type: application/json`
5. Add body (for POST/PUT): `{"name":"Foo","description":"Description"}`
6. Send the request

## Best Practices

<Tip>
  **Use TypeScript**: Always define types for request and response data to catch errors early.
</Tip>

* **Validate Input** - Always validate and sanitize user input
* **Error Handling** - Use try-catch blocks and return meaningful error messages
* **HTTP Status Codes** - Use appropriate status codes (200, 201, 400, 401, 404, 500)
* **Consistent Response Format** - Return consistent JSON structure
* **Security** - Never expose sensitive data or internal errors
* **Logging** - Log errors for debugging but don't expose details to clients

## Common Response Formats

### Success Response

```json theme={null}
{
  "success": true,
  "data": {
    "item": { ... }
  }
}
```

### Error Response

```json theme={null}
{
  "success": false,
  "error": "Error message"
}
```

### Validation Error Response

```json theme={null}
{
  "success": false,
  "errors": [
    { "field": "name", "message": "Name is required" },
    { "field": "email", "message": "Invalid email format" }
  ]
}
```

## Troubleshooting

### Endpoint Not Found (404)

1. Verify `route.json` exists and is valid
2. Check the `path` matches your request URL
3. Run `npm run build` to rebuild
4. Check extension is enabled in `config/default.json`

### Middleware Not Executing

1. Verify middleware filename uses bracket notation
2. Check middleware exports a function
3. Ensure middleware calls `next()` when done

### Body Parser Not Working

1. Verify body parser middleware is first in chain
2. Check Content-Type header is `application/json`
3. Ensure body parser is imported correctly

## Next Steps

<CardGroup cols={2}>
  <Card title="Event Subscribers" icon="bell" href="/guides/event-subscribers">
    React to API events with subscribers
  </Card>

  <Card title="GraphQL Types" icon="diagram-project" href="/api/graphql/overview">
    Learn about GraphQL API
  </Card>
</CardGroup>
