0.0.32 โ€ข Published 5 months ago

@avleon/core v0.0.32

Weekly downloads
-
License
ISC
Repository
github
Last release
5 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

5 months ago

0.0.31

5 months ago

0.0.30

5 months ago

0.0.29

5 months ago

0.0.28

5 months ago

0.0.27

5 months ago

0.0.26

5 months ago

0.0.25

6 months ago

0.0.24

6 months ago

0.0.20

7 months ago

0.0.19

7 months ago

0.0.18

7 months ago

0.0.17

7 months ago

0.0.16

7 months ago

0.0.14

7 months ago

0.0.13

7 months ago

0.0.12

7 months ago

0.0.11

7 months ago

0.0.10

7 months ago

0.0.8

7 months ago

0.0.7

7 months ago

0.0.6

7 months ago

0.0.5

8 months ago

0.0.4

9 months ago

0.0.3

9 months ago

0.0.2

9 months ago

0.0.1

9 months ago