0.0.32 โ€ข Published 7 months ago

@avleon/core v0.0.32

Weekly downloads
-
License
ISC
Repository
github
Last release
7 months ago

AvleonJs

โš ๏ธ WARNING: NOT FOR PRODUCTION USE

๐Ÿšง This project is in active development.

It is not stable and not ready for live environments.
Use only for testing, experimentation, or internal evaluation.

####โ— Risks of using this in production:

  • ๐Ÿ”„ Breaking changes may be introduced at any time
  • ๐Ÿงช Features are experimental and may be unstable
  • ๐Ÿ” Security has not been audited
  • ๐Ÿ’ฅ Potential for data loss or critical errors

Please do not deploy this in production environments.

Overview

Avleon is a powerful, TypeScript-based web framework built on top of Fastify, designed to simplify API development with a focus on decorators, dependency injection, and OpenAPI documentation. It provides a robust set of tools for building scalable, maintainable web applications with minimal boilerplate code.

Table of Contents

Features

  • Decorator-based API Development: Define controllers, routes, and middleware using TypeScript decorators
  • Dependency Injection: Built-in DI system using TypeDI for service management
  • OpenAPI/Swagger Integration: Automatic API documentation generation with support for both Swagger UI and Scalar
  • Validation: Request validation with support for class-validator and custom validation rules
  • Middleware System: Flexible middleware architecture for request processing
  • Response Handling: Standardized response formats with HTTP status codes
  • File Upload: Built-in support for multipart file uploads with file validation
  • Authentication & Authorization: Middleware for securing your API endpoints
  • Database Integration: Support for TypeORM for database operations
  • Queue System: Background job processing capabilities
  • Environment Configuration: Environment variable management
  • Logging: Integrated logging with Pino
  • Testing: Built-in testing utilities for API endpoints

Installation

npm install @avleon/core
# or
yarn add @avleon/core
# or
pnpm add @avleon/core

Quick Start

Route Based

import { Avleon, ApiController, Get, Results } from "@avleon/core";

const app = Avleon.createApplication();
app.mapGet("/", () => "Hello, Avleon");
app.run(); // or app.run(3000);

Controller Based

import { Avleon, ApiController, Get, Results } from "@avleon/core";

// Define a controller
@ApiController
class HelloController {
  @Get()
  sayHello() {
    return "Hello, Avleon!";
  }
}

// Create and start the application
const app = Avleon.createApplication();
app.useControllers([HelloController]);
app.run();

Core Concepts

Application Creation

Avleon provides a builder pattern for creating applications:

import { Avleon } from "@avleon/core";

// Create an application
const app = Avleon.createApplication();

// Configure and run the application
app.useCors();
app.useControllers([UserController]);
app.run(3000);

Controllers

Controllers are the entry points for your API requests. They are defined using the @ApiController decorator:

@ApiController("/users")
class UserController {
  // Route handlers go here
}

Route Methods

Define HTTP methods using decorators:

@Get('/')
async getUsers() {
  // Handle GET request
}

@Post('/')
async createUser(@Body() user: UserDto) {
  // Handle POST request
}

@Put('/:id')
async updateUser(@Param('id') id: string, @Body() user: UserDto) {
  // Handle PUT request
}

@Delete('/:id')
async deleteUser(@Param('id') id: string) {
  // Handle DELETE request
}

Parameter Decorators

Extract data from requests using parameter decorators:

@Get('/:id')
async getUser(
  @Param('id') id: string,
  @Query('include') include: string,
  @Header('authorization') token: string,
  @Body() data: UserDto
) {
  // Access route parameters, query strings, headers, and request body
}

Error Handling

Return standardized responses using the HttpResponse and HttpExceptions class:

@Get('/:id')
async getUser(@Param('id') id: string) {
  const user = await this.userService.findById(id);

  if (!user) {
    throw HttpExceptions.NotFound('User not found');
  }

  return HttpResponse.Ok(user);
}

Middleware

Create and apply middleware for cross-cutting concerns:

@Middleware
class LoggingMiddleware extends AppMiddleware {
  async invoke(req: IRequest) {
    console.log(`Request: ${req.method} ${req.url}`);
    return req;
  }
}

@UseMiddleware(LoggingMiddleware)
@ApiController("/users")
class UserController {
  // Controller methods
}

You can also apply middleware to specific routes:

@ApiController("/users")
class UserController {
  @UseMiddleware(LoggingMiddleware)
  @Get("/")
  async getUsers() {
    // Only this route will use the LoggingMiddleware
  }
}

Authentication & Authorization

Secure your API with authentication and authorization:

@Authorize
class JwtAuthorization extends AuthorizeMiddleware {
  authorize(roles: string[]) {
    return async (req: IRequest) => {
      // Implement JWT authentication logic
      return req;
    };
  }
}

Now register the authrization class to our app by useAuthorization function;

app.useAuthorization(JwtAuthorization);

Then you have access the AuthUser on class lavel or method lavel depending on how you use the @Authorized() decorator.

// admin.controller.ts
@Authorized()
@ApiController("/admin")
class AdminController {
  // Protected controller methods

  // protected controller has access to AuthUser in each route method
  @Get()
  async account(@AuthUser() user: User) {
    ///
  }
}

// Or protect specific routes with roles
@ApiController("/admin")
class AdminController {
  @Authorized({
    roles: ["admin"],
  })
  @Get("/")
  async adminDashboard() {
    // Only users with 'admin' role can access this
  }
}

Validation

Validate request data using class-validator:

class UserDto {
  @IsString()
  @IsNotEmpty()
  name: string;

  @IsEmail()
  email: string;

  @IsNumber()
  @Min(0)
  @Max(120)
  age: number;
}

@Post('/')
async createUser(@Body() user: UserDto) {
  // User data is automatically validated
  return user;
}

You can also use custom validation rules:

class UserDto {
  @Validate({
    type: "string",
    required: true,
    message: "Name is required",
  })
  name: string;

  @Validate({
    type: "number",
    min: 0,
    max: 120,
    message: "Age must be between 0 and 120",
  })
  age: number;
}

OpenAPI Documentation

Generate API documentation automatically:

const app = new Avleon({
  controllers: [UserController],
  openapi: {
    info: {
      title: "User API",
      version: "1.0.0",
      description: "API for managing users",
    },
    servers: [
      {
        url: "http://localhost:3000",
        description: "Development server",
      },
    ],
  },
});

You can also customize the OpenAPI UI:

app.useOpenApi(OpenApiConfig, (config) => {
  // Modify the OpenAPI configuration
  config.info.title = "Custom API Title";
  return config;
});

Advanced Features

Database Integration

Connect to databases using TypeORM:

const app = Avleon.createApplication();
app.useDataSource({
  type: "postgres",
  host: "localhost",
  port: 5432,
  username: "postgres",
  password: "password",
  database: "avleon",
  entities: [User],
  synchronize: true,
});

Or use the config class:

// datasource.config.ts
import { Config, IConfig } from "@avleon/core";

@Config
export class DataSourceConfig implements IConfig {
  // config method is mendatory
  // config method has access to environment variables by default
  config(env: Environment) {
    return {
      type: env.get("type") || "postgres",
      host: "localhost",
      port: 5432,
      username: "postgres",
      password: "password",
      database: "avleon",
      entities: [User],
      synchronize: true,
    };
  }
}
// app.ts
const app = Avleon.createApplication();
app.useDataSource(DataSourceConfig);
// ... other impments

File Uploads

Handle file uploads with multipart support:

// Configure multipart file uploads
app.useMultipart({
  destination: path.join(process.cwd(), 'uploads'),
  limits: {
    fileSize: 5 * 1024 * 1024 // 5MB
  }
});

// In your controller
@Post('/upload')
async uploadFile(@File() file: any) {
  // Process uploaded file
  return HttpResponse.Ok({ filename: file.filename });
}

Static Files

Serve static files:

app.useStaticFiles({
  path: path.join(process.cwd(), "public"),
  prefix: "/static/",
});

Testing

Test your API endpoints with the built-in testing utilities:

import { TestBuilder } from "@avleon/core";

const testBuilder = TestBuilder.createBuilder();
const app = testBuilder.getTestApplication({
  controllers: [UserController],
});

// Test your API endpoints
const response = await app.get("/users");
expect(response.statusCode).toBe(200);

Configuration

Configure your application with environment variables:

// .env
PORT=3000
DATABASE_URL=postgres://user:password@localhost:5432/db

// app.ts
import { Environment } from '@avleon/core';

const env = new Environment();
env.load();

const app = new Avleon({
  controllers: [UserController],
  env: {
    port: 'PORT',
    databaseUrl: 'DATABASE_URL',
  },
});

Route Mapping

Avleon provides several methods for mapping routes in your application:

mapGet

The mapGet method is used to define GET routes in your application. It takes a path string and a handler function as parameters.

app.mapGet("/users", async (req, res) => {
  // Handle GET request to /users
  return { users: [] };
});

mapPost

The mapPost method is used to define POST routes in your application. It takes a path string and a handler function as parameters.

app.mapPost("/users", async (req, res) => {
  // Handle POST request to /users
  const userData = req.body;
  // Process user data
  return { success: true };
});

mapPut

The mapPut method is used to define PUT routes in your application. It takes a path string and a handler function as parameters.

app.mapPut("/users/:id", async (req, res) => {
  // Handle PUT request to /users/:id
  const userId = req.params.id;
  const userData = req.body;
  // Update user data
  return { success: true };
});

mapDelete

The mapDelete method is used to define DELETE routes in your application. It takes a path string and a handler function as parameters.

app.mapDelete("/users/:id", async (req, res) => {
  // Handle DELETE request to /users/:id
  const userId = req.params.id;
  // Delete user
  return { success: true };
});

Each of these methods returns a route object that can be used to add middleware or Swagger documentation to the route.

app
  .mapGet("/users", async (req, res) => {
    // Handler function
  })
  .useMiddleware([AuthMiddleware])
  .useSwagger({
    summary: "Get all users",
    description: "Retrieves a list of all users",
    tags: ["users"],
    response: {
      200: {
        description: "Successful response",
        content: {
          "application/json": {
            schema: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  id: { type: "string" },
                  name: { type: "string" },
                },
              },
            },
          },
        },
      },
    },
  });

License

ISC

Author

Tareq Hossain - GitHub

0.0.32

7 months ago

0.0.31

7 months ago

0.0.30

7 months ago

0.0.29

7 months ago

0.0.28

7 months ago

0.0.27

8 months ago

0.0.26

8 months ago

0.0.25

8 months ago

0.0.24

8 months ago

0.0.20

9 months ago

0.0.19

9 months ago

0.0.18

9 months ago

0.0.17

9 months ago

0.0.16

9 months ago

0.0.14

9 months ago

0.0.13

9 months ago

0.0.12

9 months ago

0.0.11

9 months ago

0.0.10

9 months ago

0.0.8

10 months ago

0.0.7

10 months ago

0.0.6

10 months ago

0.0.5

10 months ago

0.0.4

12 months ago

0.0.3

12 months ago

0.0.2

12 months ago

0.0.1

12 months ago