or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

application.mdhooks.mdindex.mdservice-interfaces.mdservices.md
tile.json

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;