Server API
Ecopages provides a powerful server API that allows you to create endpoints and handle server-side logic with ease.
Basic Usage
Create an app.ts
file in your project root:
import { EcopagesApp } from '@ecopages/core/adapters/bun/create-app';
import appConfig from './eco.config';
const app = new EcopagesApp({ appConfig });
app.get('/api/hello', async () => {
return new Response('Hello World');
});
await app.start();
HTTP Methods
The server supports all standard HTTP methods:
app.get('/api/resource', handler);
app.post('/api/resource', handler);
app.put('/api/resource', handler);
app.patch('/api/resource', handler);
app.delete('/api/resource', handler);
app.options('/api/resource', handler);
app.head('/api/resource', handler);
Route Parameters
You can define dynamic route parameters using the :param
syntax:
app.get('/api/users/:id/posts/:postId', async ({ request }) => {
const { id, postId } = request.params;
return new Response(JSON.stringify({ userId: id, postId }));
});
Type Safety
Ecopages leverages TypeScript to provide strong type safety for your API handlers, especially for route parameters.
While you can define handlers directly, ensuring the request.params
type matches the path
string requires careful manual typing. To simplify this and improve code organization, Ecopages provides adapter-specific helper functions.
Using defineBunApiHandler
When using the Bun adapter, you can use the defineBunApiHandler
helper function. This function automatically infers the parameter types from the path
string literal, ensuring your request.params
object is correctly typed without explicit annotations.
// Import the adapter-specific helper
import { defineBunApiHandler } from '@ecopages/core/adapters/bun/define-handler'; // Adjust path if needed
// Define the handler using the helper
const getUserHandler = defineBunApiHandler({
method: 'GET',
path: '/api/users/:id', // Type of 'id' is inferred from here
handler: async ({ request }) => {
// request.params is automatically typed as { id: string }
const { id } = request.params;
// Fetch user logic...
const user = { id: id, name: 'Example User' };
if (!user) {
return new Response('User not found', { status: 404 });
}
return new Response(JSON.stringify(user));
},
});
// Register the handler with the app
app.get(getUserHandler.path, getUserHandler.handler);
// You can define multiple handlers this way and keep them organized
const updateUserHandler = defineBunApiHandler({
method: 'PUT',
path: '/api/users/:id',
handler: async ({ request }) => {
const { id } = request.params;
// Update user logic...
return new Response(JSON.stringify({ id, message: 'User updated' }));
}
});
app.put(updateUserHandler.path, updateUserHandler.handler);
Benefits of Using defineBunApiHandler
Using defineBunApiHandler offers several advantages:
- Automatic Parameter Typing: Eliminates the need to manually type request.params.
- Improved Readability: Keeps the handler definition concise.
- Enhanced Organization: Encourages defining handlers as separate, reusable constants before registering them.
- Reduced Errors: Prevents type mismatches between the path string and the parameters used in the handler.
Static Site Generation
During static site generation, the server can still handle API requests, making it possible to generate static content from API responses:
export const getStaticProps: GetStaticProps = async ({ appConfig }) => {
const response = await fetch(`${appConfig.baseUrl}/api/data`);
const data = await response.json();
return {
props: { data },
};
};
Development Server
The development server includes:
- Hot Module Replacement (HMR) (beta)
- Automatic route reloading
- API endpoint hot reloading
- Static file serving
- Error handling with detailed stack traces
Production Build
When building for production:
- Static routes are pre-rendered
- API routes are preserved for server-side handling
- Assets are optimized and collected
- Development-only code is stripped
Error Handling
The server includes built-in error handling:
app.get('/api/error', async () => {
throw new Error('Something went wrong');
// Will return a 500 response with error details in development
// and a safe error message in production
});
Configuration
Server configuration can be customized in your eco.config.ts
:
const config = await new ConfigBuilder()
.setBaseUrl('http://localhost:3000')
// ... other config
.build();