SummerJS Framework

website·Indexed 29 days ago

https://summerjs.dev

A secure, high-quality enterprise backend framework featuring runtime TypeScript type validation, DTO conversion, and dependency injection. It includes built-in support for RPC, custom decorators, and various extensions such as TypeORM, Elasticsearch, GraphQL, Socket.IO, IORedis, and Swagger Docs.

Tokens
16.4K
Snippets
106
Records
115
Agent score
48%

What's inside SummerJS

  1. Overview of Summer backend framework features

    Summer is a secure, high-quality enterprise backend framework designed for developer experience. Key features include:

    • Runtime TypeScript Validation: Uses TypeScript for request validation to increase security and reliability.
    • DTO Conversion: Provides built-in functions for safe Data Transfer Object (DTO) conversion.
    • Custom Decorators: Supports decorators for request parameter extraction, authentication, method interception, and result modification.
    • Single-File Deployment: Uses esbuild to pack code into a single runnable JavaScript file, making it compatible with Kubernetes and Serverless environments without configuration changes.
    • Swagger Integration: Automatically generates OpenAPI 3.0.x documentation using runtime TypeScript and integrates with TypeORM column comments and decorators like @Max() and Optional(?).
    • Extensions: Supports Redis, TypeORM (MySQL and MongoDB), GraphQL, ElasticSearch, and Socket.IO.
  2. Overview of SummerJS developer features

    SummerJS is designed to be programmer-friendly, focusing on simplicity and power. Key capabilities include strict runtime TypeScript typing validation, automatic Swagger documentation, support for custom decorators, and a serverless-compatible build process. It provides rich extensions for integrating with MySQL, Redis, GraphQL, and supports RPC.
  3. Understand automatic response serialization in Summer

    Summer automatically serializes data returned from controller methods. If a method returns an object, it is serialized to a JSON string with the Content-Type header set to application/json. If a method returns a string or other JavaScript primitive type, it is converted to a string with the Content-Type header set to text/html.
  4. Access the Request Context in Summer.js

    Summer creates a Context object at the start of every request. This object contains information about the request, response, cookies, session, and the current invocation. You can access the context in two ways: by using the @Context decorator in a controller method parameter, or by calling the getContext() API function.
    import { Context, Controller, Ctx, Get } from '@summer-js/summer'
    
    @Controller
    export class ContextController {
      @Get('/context')
      context(@Context context: Context) {
        // Access via parameter
        console.log(context)
        
        // OR access via API
        // const context = getContext()
      }
    }
  5. Pass custom data through the request lifecycle

    The Context object includes a data property used to store and carry custom information across the entire request period. This is typically used in middleware to attach data that can later be accessed by custom decorators or controllers.
    import { Middleware, Context } from '@summer-js/summer'
    
    @Middleware({ order: 0 })
    export class DataMiddleware {
      async process(ctx: Context, next: any) {
        // Store custom data
        ctx.data.customData = 'abc'
        await next()
      }
    }
    
    // The value 'abc' is now available in ctx.data.customData 
    // for subsequent controllers or decorators in the request chain.
  6. Set up and run DB migrations with TypeORM

    To manage migrations, install ts-node and create an ormconfig.ts file for the TypeORM CLI. Use the DBNamingStrategy from @summer-js/typeorm to maintain naming consistency. You can automate migration execution during server startup using the before hook in summerStart.
    npm install ts-node --save-dev

    // ormconfig.ts import { DataSource } from 'typeorm' import { DBNamingStrategy } from '@summer-js/typeorm'

    export default new DataSource({ type: 'mysql', host: 'localhost', database: 'summer-db', username: 'root', password: 'root', namingStrategy: new DBNamingStrategy(), entities: ['./src/entity/**/*.ts'] })

    // package.json script // "generate-migration": "typeorm-ts-node-commonjs migration:generate src/migrations/migration -d ormconfig.ts -p"

    // src/index.ts (Running migrations on start) import { getDataSource } from '@summer-js/typeorm' import { summerStart, Logger } from '@summer-js/summer'

    summerStart({ async before(config) { const output = await getDataSource('DATA_SOURCE').runMigrations() output.forEach((m) => Logger.info('Run migration: ' + m.name)) }, after(config) {} })

  7. Implement global request interception with Middleware

    Middleware in SummerJS allows you to intercept every request before and after it reaches the controllers. You define a middleware by creating a class decorated with @Middleware(). The process method receives the Context and a next function. Calling await next() passes control to the next middleware or controller in the chain, allowing you to execute logic both before and after the request is handled. The order property in the decorator determines the execution sequence.
    import { Middleware, Context } from '@summer-js/summer';
    
    @Middleware({ order: 0 })
    export class AuthMiddleware {
      async process(ctx: Context, next: any) {
        try {
          // Logic before controller
          await next();
          // Logic after controller
        } catch (err) {
          console.log(err);
          ctx.response.statusCode = 500;
          ctx.response.body = 'Server Error';
        }
      }
    }
  8. Install Elasticsearch extension for SummerJS

    To use Elasticsearch with SummerJS, you need to install both the official Elasticsearch client and the SummerJS Elasticsearch wrapper.
    npm install @elastic/elasticsearch
    npm install @summer-js/elasticsearch
  9. Create a custom class or method decorator in SummerJS

    SummerJS provides three functions for intercepting method execution: createMethodDecorator (methods only), createClassDecorator (all methods in a class), and createClassAndMethodDecorator (both). These decorators can modify the request context, change the response, or decide whether to call the original method using invokeMethod.
    import { Controller, createClassAndMethodDecorator, Get, Put } from '@summer-js/summer'
    import jwt from 'jsonwebtoken'
    
    // Create a decorator that handles authentication for both classes and methods
    export const RequireLogin = createClassAndMethodDecorator(async (ctx, invokeMethod) => {
      const token = ctx.request.headers['authentication']
      try {
        jwt.verify(token, 'secret_key')
        // Proceed to the original method
        return await invokeMethod(ctx.invocation.params)
      } catch (e) {
        ctx.response.statusCode = 401
        ctx.response.body = 'Unauthorized'
      }
    })
    
    @Controller
    @RequireLogin // Intercepts all methods in this class
    export class LoginController {
      @Get('/me')
      info() {}
    }
  10. Deploy SummerJS using Docker and Kubernetes

    Create a Dockerfile that copies the contents of the build directory into the image. Use node --enable-source-maps index.js as the entry point.
    FROM node:16
    
    WORKDIR /usr/src/app
    
    COPY ./build .
    
    EXPOSE 80
    CMD [ "node", "--enable-source-maps", "index.js" ]
    # Build image
    docker build . -t <your username>/node-app
    
    # Run container
    docker run -p 80:80 -d <your username>/node-app
  11. Intercept requests for authentication using custom decorators

    Use createClassAndMethodDecorator to create a middleware-like interceptor that can validate request headers before executing a controller method. If the validation fails, you can throw a ResponseError to return a specific HTTP status code to the client.
    import { Controller, Get, createClassAndMethodDecorator, ResponseError } from '@summer-js/summer'
    
    const AuthAccessKey = createClassAndMethodDecorator(async (ctx, invokeMethod) => {
      if (ctx.request.headers['access-key'] === 'xxxxxx') {
        return await invokeMethod(ctx.invocation.params)
      }
      throw new ResponseError(403, 'Forbidden')
    })
    
    @Controller
    export class AppController {
      @AuthAccessKey
      @Get('/access')
      info() {
        return "it's works"
      }
    }
  12. Validate complex objects and nested DTOs in request bodies

    Summer JS supports runtime validation of complex objects. By defining a class as a DTO (Data Transfer Object) and using it as the type for the @Body decorator in a controller, Summer validates the incoming request against the class properties, including nested objects and enums.
    // src/dto/request/book.ts
    export enum Gender {
      Female = 1,
      Male = 2
    }
    
    export class Person {
      name: string;
      age: int;
      gender: Gender;
    }
    
    export class Book {
      title: string;
      author: Person;
    }
    
    // src/controller/BookController.ts
    import { Controller, Post, Body } from '@summer-js/summer';
    import { Book } from '../dto/request/book'
    
    @Controller
    export class BookController {
      @Post('/books')
      addBook(@Body book: Book) {
        console.log(typeof book, book);
      }
    }