CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-feathersjs--feathers

A framework for real-time applications and REST API with JavaScript and TypeScript

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

service-interfaces.mddocs/

Service Interfaces

Standard service method interfaces and type definitions for implementing Feathers services.

Capabilities

Service Methods Interface

Core CRUD operations that Feathers services can implement.

interface ServiceMethods<
  Result = any,
  Data = Partial<Result>,
  ServiceParams = Params,
  PatchData = Partial<Data>
> {
  /**
   * Retrieve multiple records, optionally filtered and paginated
   * @param params - Query parameters including filters and pagination
   * @returns Promise resolving to results or paginated results
   */
  find(params?: ServiceParams & { paginate?: PaginationParams }): Promise<Result | Result[]>;

  /**
   * Retrieve a single record by ID
   * @param id - The record identifier
   * @param params - Query parameters
   * @returns Promise resolving to the record
   */
  get(id: Id, params?: ServiceParams): Promise<Result>;

  /**
   * Create a new record
   * @param data - The data for the new record
   * @param params - Query parameters
   * @returns Promise resolving to the created record
   */
  create(data: Data, params?: ServiceParams): Promise<Result>;

  /**
   * Replace a record by ID (full update)
   * @param id - The record identifier, or null to update multiple records
   * @param data - The replacement data
   * @param params - Query parameters
   * @returns Promise resolving to updated record(s)
   */
  update(id: NullableId, data: Data, params?: ServiceParams): Promise<Result | Result[]>;

  /**
   * Partially update a record by ID
   * @param id - The record identifier, or null to patch multiple records
   * @param data - The partial update data
   * @param params - Query parameters
   * @returns Promise resolving to updated record(s)
   */
  patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>;

  /**
   * Remove a record by ID
   * @param id - The record identifier, or null to remove multiple records
   * @param params - Query parameters
   * @returns Promise resolving to removed record(s)
   */
  remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]>;

  /**
   * Initialize the service when the application starts
   * @param app - The Feathers application instance
   * @param path - The service path
   */
  setup?(app: Application, path: string): Promise<void>;

  /**
   * Clean up the service when the application shuts down
   * @param app - The Feathers application instance
   * @param path - The service path
   */
  teardown?(app: Application, path: string): Promise<void>;
}

Service Interface (Partial)

Optional service interface where no methods are required, allowing flexible service implementations.

type ServiceInterface<
  Result = any,
  Data = Partial<Result>,
  ServiceParams = Params,
  PatchData = Partial<Data>
> = Partial<ServiceMethods<Result, Data, ServiceParams, PatchData>>;

Usage Examples:

import { ServiceInterface, Params } from "@feathersjs/feathers";

// Simple read-only service
class ReadOnlyService implements ServiceInterface {
  data = [
    { id: 1, name: "Item 1" },
    { id: 2, name: "Item 2" }
  ];

  async find() {
    return this.data;
  }

  async get(id: number) {
    return this.data.find(item => item.id === id);
  }
}

// Full CRUD service with typed parameters
interface Todo {
  id: number;
  text: string;
  completed: boolean;
  createdAt: Date;
}

interface TodoData {
  text: string;
  completed?: boolean;
}

interface TodoParams extends Params {
  user?: { id: number };
}

class TodoService implements ServiceInterface<Todo, TodoData, TodoParams> {
  todos: Todo[] = [];

  async find(params?: TodoParams) {
    let results = this.todos;
    
    if (params?.query?.completed !== undefined) {
      results = results.filter(todo => todo.completed === params.query.completed);
    }
    
    return results;
  }

  async get(id: number, params?: TodoParams) {
    return this.todos.find(todo => todo.id === id);
  }

  async create(data: TodoData, params?: TodoParams) {
    const todo: Todo = {
      id: Date.now(),
      text: data.text,
      completed: data.completed || false,
      createdAt: new Date()
    };
    
    this.todos.push(todo);
    return todo;
  }

  async patch(id: number, data: Partial<TodoData>, params?: TodoParams) {
    const todo = this.todos.find(t => t.id === id);
    if (todo) {
      Object.assign(todo, data);
    }
    return todo;
  }

  async remove(id: number, params?: TodoParams) {
    const index = this.todos.findIndex(t => t.id === id);
    if (index !== -1) {
      return this.todos.splice(index, 1)[0];
    }
  }

  async setup(app: Application, path: string) {
    console.log(`TodoService setup at path: ${path}`);
  }

  async teardown(app: Application, path: string) {
    console.log(`TodoService teardown at path: ${path}`);
  }
}

Service Overloads

Method overloads for handling different parameter combinations.

interface ServiceOverloads<
  Result = any,
  Data = Partial<Result>,
  ServiceParams = Params,
  PatchData = Partial<Data>
> {
  /**
   * Create multiple records at once
   */
  create?(data: Data[], params?: ServiceParams): Promise<Result[]>;

  /**
   * Update a specific record by ID
   */
  update?(id: Id, data: Data, params?: ServiceParams): Promise<Result>;

  /**
   * Update all records matching query
   */
  update?(id: null, data: Data, params?: ServiceParams): Promise<Result[]>;

  /**
   * Patch a specific record by ID
   */
  patch?(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>;

  /**
   * Patch all records matching query
   */
  patch?(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>;

  /**
   * Remove a specific record by ID
   */
  remove?(id: Id, params?: ServiceParams): Promise<Result>;

  /**
   * Remove all records matching query
   */
  remove?(id: null, params?: ServiceParams): Promise<Result[]>;
}

Complete Service Type

Complete service interface combining base methods and overloads.

type Service<
  Result = any,
  Data = Partial<Result>,
  ServiceParams = Params,
  PatchData = Partial<Data>
> = ServiceMethods<Result, Data, ServiceParams> & ServiceOverloads<Result, Data, ServiceParams, PatchData>;

Client Service Interface

Interface for client-side services (e.g., REST, WebSocket clients).

interface ClientService<
  Result = any,
  Data = Partial<Result>,
  PatchData = Data,
  FindResult = Paginated<Result>,
  P = Params
> {
  find(params?: P): Promise<FindResult>;
  get(id: Id, params?: P): Promise<Result>;
  
  create(data: Data[], params?: P): Promise<Result[]>;
  create(data: Data, params?: P): Promise<Result>;
  
  update(id: Id, data: Data, params?: P): Promise<Result>;
  update(id: NullableId, data: Data, params?: P): Promise<Result | Result[]>;
  update(id: null, data: Data, params?: P): Promise<Result[]>;
  
  patch(id: NullableId, data: PatchData, params?: P): Promise<Result | Result[]>;
  patch(id: Id, data: PatchData, params?: P): Promise<Result>;
  patch(id: null, data: PatchData, params?: P): Promise<Result[]>;
  
  remove(id: NullableId, params?: P): Promise<Result | Result[]>;
  remove(id: Id, params?: P): Promise<Result>;
  remove(id: null, params?: P): Promise<Result[]>;
}

Custom Methods

Interface for defining custom service methods beyond the standard CRUD operations.

/**
 * Interface for custom service methods
 */
type CustomMethod<T = any, R = T, P extends Params = Params> = (data: T, params?: P) => Promise<R>;

/**
 * Type helper for defining multiple custom methods
 */
type CustomMethods<T extends { [key: string]: [any, any] }> = {
  [K in keyof T]: (data: T[K][0], params?: Params) => Promise<T[K][1]>;
};

Usage Example:

interface MessageServiceCustomMethods {
  markAsRead: CustomMethod<{ messageId: number }, { success: boolean }>;
  bulkDelete: CustomMethod<{ ids: number[] }, { deleted: number }>;
}

class MessageService implements ServiceInterface, MessageServiceCustomMethods {
  // Standard CRUD methods...
  
  async markAsRead(data: { messageId: number }, params?: Params) {
    // Mark message as read
    return { success: true };
  }

  async bulkDelete(data: { ids: number[] }, params?: Params) {
    // Delete multiple messages
    return { deleted: data.ids.length };
  }
}

// Register with custom methods
app.use("messages", new MessageService(), {
  methods: ["find", "get", "create", "markAsRead", "bulkDelete"]
});

Type Utilities

/**
 * Extract the Result type from a service
 */
type ServiceGenericType<S> = S extends ServiceInterface<infer T> ? T : any;

/**
 * Extract the Data type from a service
 */
type ServiceGenericData<S> = S extends ServiceInterface<infer _T, infer D> ? D : any;

/**
 * Extract the Params type from a service
 */
type ServiceGenericParams<S> = S extends ServiceInterface<infer _T, infer _D, infer P> ? P : any;

docs

application.md

hooks.md

index.md

service-interfaces.md

services.md

tile.json