A framework for real-time applications and REST API with JavaScript and TypeScript
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Standard service method interfaces and type definitions for implementing Feathers services.
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>;
}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}`);
}
}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 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>;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[]>;
}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"]
});/**
* 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;