Skip to main content

Getting Started with EdgeMaster

This guide will help you build your first edge application with EdgeMaster in just a few minutes.

Prerequisites

Before you begin, ensure you have:

  • Node.js 16 or higher
  • npm or yarn
  • Cloudflare account (for deployment)
  • Basic understanding of TypeScript/JavaScript
  • Familiarity with async/await

Installation

1. Install EdgeMaster

npm install edge-master

2. Install Development Dependencies

For Cloudflare Workers:

npm install -D wrangler @cloudflare/workers-types typescript

Your First Route

Let's create a simple "Hello World" API.

Step 1: Create Project Structure

mkdir my-edge-app
cd my-edge-app
npm init -y
npm install edge-master

Step 2: Create src/index.ts

import { EdgeController, RouteHandler, Task, json } from 'edge-master';

// Create the app
const app = new EdgeController();

// Add a simple route
app.GET('/hello', new RouteHandler(new Task({
do: async () => json({ message: 'Hello World!' })
})));

// Export for Cloudflare Workers
export default {
fetch: (request: Request) => app.handleRequest({ req: request })
};

Step 3: Create wrangler.toml

name = "my-edge-app"
main = "src/index.ts"
compatibility_date = "2024-01-01"

Step 4: Create tsconfig.json

{
"compilerOptions": {
"target": "ES2021",
"module": "ES2022",
"lib": ["ES2021"],
"types": ["@cloudflare/workers-types"],
"strict": true
}
}

Step 5: Run Locally

npx wrangler dev

Visit http://localhost:8787/hello - you should see:

{
"message": "Hello World!"
}

🎉 Congratulations! You've created your first EdgeMaster application!


Adding More Routes

Let's add more functionality to your application.

HTTP Method Helpers

import { json, badRequest, parseJSON } from 'edge-master';

// GET route
app.GET('/users', new RouteHandler(new Task({
do: async () => json({ users: [] })
})));

// POST route
app.POST('/users', new RouteHandler(new Task({
do: async ({ req }) => {
const body = await parseJSON(req);

if (!body.name || !body.email) {
return badRequest('Name and email are required');
}

return json({ user: body }, { status: 201 });
}
})));

// PUT route
app.PUT('/users/:id', new RouteHandler(new Task({
do: async ({ req }) => {
const id = new URL(req.url).pathname.split('/').pop();
const body = await parseJSON(req);

return json({ user: { id, ...body } });
}
})));

// DELETE route
app.DELETE('/users/:id', new RouteHandler(new Task({
do: async ({ req }) => {
const id = new URL(req.url).pathname.split('/').pop();

return json({ message: 'User deleted', id });
}
})));

Adding Interceptors

Interceptors are middleware that run before or after route handling.

CORS Support

import { corsInterceptor } from 'edge-master';

app.addInterceptor(corsInterceptor({
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: false
}));

Request Logging

import { loggingInterceptor } from 'edge-master';

const { request, response } = loggingInterceptor({
level: 'info',
logTiming: true
});

app.addInterceptor(request); // Log incoming requests
app.addInterceptor(response); // Log outgoing responses

Request & Response Handling

Parsing Request Bodies

import { parseJSON, parseFormData, parseText } from 'edge-master';

app.POST('/api/data', new RouteHandler(new Task({
do: async ({ req }) => {
// Parse JSON body
const jsonData = await parseJSON(req);

// Or parse form data
// const formData = await parseFormData(req);

// Or parse as text
// const textData = await parseText(req);

return json({ received: jsonData });
}
})));

Query Parameters

import { getQuery, parseQuery } from 'edge-master';

app.GET('/search', new RouteHandler(new Task({
do: async ({ req }) => {
// Get single parameter
const query = getQuery(req, 'q');
const page = getQuery(req, 'page') || '1';

// Or get all parameters
const allParams = parseQuery(req);

return json({
query,
page: parseInt(page),
params: Object.fromEntries(allParams)
});
}
})));

Response Helpers

import {
json,
text,
html,
redirect,
notFound,
badRequest,
unauthorized
} from 'edge-master';

// JSON response
app.GET('/data', new RouteHandler(new Task({
do: async () => json({ data: [1, 2, 3] })
})));

// Text response
app.GET('/plain', new RouteHandler(new Task({
do: async () => text('Plain text response')
})));

// HTML response
app.GET('/page', new RouteHandler(new Task({
do: async () => html('<h1>Hello World</h1>')
})));

// Redirect
app.GET('/old-path', new RouteHandler(new Task({
do: async () => redirect('/new-path')
})));

// Error responses
app.GET('/not-found', new RouteHandler(new Task({
do: async () => notFound('Resource not found')
})));

Route Organization

Route Grouping

Organize related routes under a common prefix:

app.group('/api/v1', (api) => {
api.GET('/users', listUsersHandler);
api.POST('/users', createUserHandler);
api.GET('/posts', listPostsHandler);
api.POST('/posts', createPostHandler);
});

// Results in:
// GET /api/v1/users
// POST /api/v1/users
// GET /api/v1/posts
// POST /api/v1/posts

Nested Groups

app.group('/api', (api) => {
api.group('/v1', (v1) => {
v1.GET('/users', usersHandlerV1);
});

api.group('/v2', (v2) => {
v2.GET('/users', usersHandlerV2);
});
});

// Results in:
// GET /api/v1/users
// GET /api/v2/users

Error Handling

Default Error Handling

EdgeMaster automatically handles errors:

  • 404 for unmatched routes
  • 500 for uncaught errors

Custom Error Handlers

// Custom 404 handler
app.onNotFound(async ({ req }) => {
const url = new URL(req.url);

return json({
error: 'Not Found',
path: url.pathname,
message: `Route ${url.pathname} does not exist`
}, { status: 404 });
});

// Custom error handler
app.onError(async (error, ctx) => {
console.error('Error:', error);

return json({
error: 'Internal Server Error',
message: error.message
}, { status: 500 });
});

Complete Example

Here's a complete REST API with all features:

import {
EdgeController,
RouteHandler,
Task,
json,
parseJSON,
getQuery,
corsInterceptor,
loggingInterceptor,
badRequest,
notFound,
} from 'edge-master';

const app = new EdgeController();

// Add interceptors
app.addInterceptor(corsInterceptor({ origin: '*' }));
const { request, response } = loggingInterceptor();
app.addInterceptor(request);
app.addInterceptor(response);

// In-memory storage
const users = new Map();

// Initialize with sample data
users.set('1', { id: '1', name: 'Alice', email: 'alice@example.com' });
users.set('2', { id: '2', name: 'Bob', email: 'bob@example.com' });

// API routes
app.group('/api', (api) => {
// List users with pagination
api.GET('/users', new RouteHandler(new Task({
do: async ({ req }) => {
const page = parseInt(getQuery(req, 'page') || '1');
const limit = 10;

const userList = Array.from(users.values());
const start = (page - 1) * limit;
const paginatedUsers = userList.slice(start, start + limit);

return json({
users: paginatedUsers,
page,
total: userList.length
});
}
})));

// Get user by ID
api.GET('/users/', new RouteHandler(new Task({
do: async ({ req }) => {
const id = new URL(req.url).pathname.split('/').pop();
const user = users.get(id);

if (!user) {
return notFound(`User ${id} not found`);
}

return json({ user });
}
})));

// Create user
api.POST('/users', new RouteHandler(new Task({
do: async ({ req }) => {
const body = await parseJSON(req);

if (!body.name || !body.email) {
return badRequest('Name and email are required');
}

const user = {
id: (users.size + 1).toString(),
name: body.name,
email: body.email
};

users.set(user.id, user);

return json({ user }, { status: 201 });
}
})));
});

// Error handlers
app.onNotFound(async () => notFound('Endpoint not found'));
app.onError(async (error) => json({ error: error.message }, { status: 500 }));

// Export
export default {
fetch: (request: Request) => app.handleRequest({ req: request })
};

Deployment

Deploy to Cloudflare Workers

# Login to Cloudflare (first time only)
npx wrangler login

# Deploy
npx wrangler deploy

Your application will be deployed to: https://my-edge-app.<your-subdomain>.workers.dev

Environment Variables

Create .dev.vars for local development:

API_KEY=your-api-key-here
JWT_SECRET=your-jwt-secret

For production, use Wrangler secrets:

npx wrangler secret put API_KEY
npx wrangler secret put JWT_SECRET

Access in code:

export default {
fetch: (request: Request, env: any) => {
const apiKey = env.API_KEY;
return app.handleRequest({ req: request, env });
}
};

Next Steps

Now that you have a basic application running, explore more features:

📖 Learn Core Concepts

🔒 Add Authentication

⚡ Improve Performance

💡 Explore Examples


Need Help?


Happy coding! 🚀