mirror of
https://github.com/feathersjs/feathers.git
synced 2026-02-01 17:37:38 +00:00
chore(docs): Review and update core API docs (#2808)
This commit is contained in:
parent
01dfa2a802
commit
5792b9214f
@ -17,7 +17,6 @@ npm install @feathersjs/feathers --save
|
||||
|
||||
The core `@feathersjs/feathers` module provides the ability to initialize a new Feathers application instance. It works in Node, React Native and the browser (see the [client](./client.md) chapter for more information). Each instance allows for registration and retrieval of [services](./services.md), [hooks](./hooks.md), plugin configuration, and getting and setting configuration options. An initialized Feathers application is referred to as the **app object**.
|
||||
|
||||
|
||||
```ts
|
||||
import { feathers } from '@feathersjs/feathers'
|
||||
|
||||
@ -37,7 +36,6 @@ const app = feathers<ServiceTypes, Configuration>()
|
||||
|
||||
`app.use(path, service [, options]) -> app` allows registering a [service object](./services.md) on a given `path`.
|
||||
|
||||
|
||||
```ts
|
||||
import { feathers, type Id } from '@feathersjs/feathers'
|
||||
|
||||
@ -64,15 +62,15 @@ app.use('messages', new MessageService())
|
||||
const message = await app.service('messages').get('test')
|
||||
```
|
||||
|
||||
<BlockQuote type="info">
|
||||
### path
|
||||
|
||||
`path` can be `/` to register a service at the root level.
|
||||
The `path` is a string that should be URL friendly and may contain `/` as a separator. `path` can also be `/` to register a service at the root level. A path may contain placeholders in the form of `:userId/messages` which will be included in `params.route` by a transport.
|
||||
|
||||
</BlockQuote>
|
||||
### options
|
||||
|
||||
`options` can contain the following additional options for the service:
|
||||
The following options are available:
|
||||
|
||||
- `methods` (default: `['find', 'get', 'create', 'patch', 'update','remove']`) - A list of official and [custom service methods](services.md#custom-methods) exposed by this service. When using this option **all** method names that should be available externally must be passed. Those methods will automatically be available for use with [hooks](./hooks).
|
||||
- `methods` (default: `['find', 'get', 'create', 'patch', 'update','remove']`) - A list of official and [custom service methods](services.md#custom-methods) that should be available to clients. When using this option **all** method names that should be available externally must be passed. Those methods will automatically be available for use with [hooks](./hooks).
|
||||
- `events` - A list of [public custom events sent by this service](./events.md#custom-events)
|
||||
|
||||
```ts
|
||||
@ -109,22 +107,48 @@ app.use('messages', new MessageService(), {
|
||||
})
|
||||
```
|
||||
|
||||
## .unuse(path)
|
||||
|
||||
`app.unuse(path)` unregisters an existing service on `path` and calls the services [.teardown method](./services.md#teardownapp-path) if it is implemented.
|
||||
|
||||
## .service(path)
|
||||
|
||||
`app.service(path) -> service` returns the [service object](./services.md) for the given path. Feathers internally creates a new object from each registered service. This means that the object returned by `app.service(path)` will provide the same methods and functionality as your original service object but also functionality added by Feathers and its plugins like [service events](./events.md) and [additional methods](./services.md#feathers-functionality).
|
||||
|
||||
```ts
|
||||
const messageService = app.service('messages');
|
||||
const messageService = app.service('messages')
|
||||
|
||||
const message = await messageService.get('test');
|
||||
const message = await messageService.get('test')
|
||||
|
||||
console.log(message);
|
||||
console.log(message)
|
||||
|
||||
messageService.on('created', (message: Message) => {
|
||||
console.log('Created a todo')
|
||||
})
|
||||
```
|
||||
|
||||
<BlockQuote type="info" label="Note">
|
||||
|
||||
Note that a server side `app.service(path)` only allows the original service name (e.g. `app.service(':userId/messages')`) and does not parse placeholders. To get a service with route paramters use [.lookup](#lookuppath)
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
## .lookup(path)
|
||||
|
||||
`app.lookup(path)` allows to look up a full path and will return the `data` (route parameters) and `service` **on the server**.
|
||||
|
||||
```ts
|
||||
const lookup = app.lookup('messages/4321')
|
||||
|
||||
// lookup.service -> app.service('messages')
|
||||
// lookup.data -> { __id: '4321' }
|
||||
|
||||
// `lookup.dta` needs to be passed as `params.route`
|
||||
lookup.service.find({
|
||||
route: lookup.data
|
||||
})
|
||||
```
|
||||
|
||||
## .hooks(hooks)
|
||||
|
||||
`app.hooks(hooks) -> app` allows registration of application-level hooks. For more information see the [application hooks section in the hooks chapter](./hooks.md#application-hooks).
|
||||
@ -139,23 +163,22 @@ messageService.on('created', (message: Message) => {
|
||||
|
||||
```ts
|
||||
const setupService = (app: Application) => {
|
||||
app.use('/todos', todoService);
|
||||
app.use('/todos', todoService)
|
||||
}
|
||||
|
||||
app.configure(setupService);
|
||||
app.configure(setupService)
|
||||
```
|
||||
|
||||
|
||||
## .setup([server])
|
||||
|
||||
`app.setup([server]) -> Promise<app>` is used to initialize all services by calling each [services .setup(app, path)](services.md#setupapp-path) method (if available).
|
||||
It will also use the `server` instance passed (e.g. through `http.createServer`) to set up SocketIO (if enabled) and any other provider that might require the server instance. You can register [application hooks](./hooks.md#application-hooks) on setup to e.g. set up database connections and other things required to be initialized on startup in a certain order.
|
||||
It will also use the `server` instance passed (e.g. through `http.createServer`) to set up SocketIO (if enabled) and any other provider that might require the server instance. You can register [application setup hooks](./hooks.md#setup-and-teardown) to e.g. set up database connections and other things required to be initialized on startup in a certain order.
|
||||
|
||||
Normally `app.setup` will be called automatically when starting the application via [app.listen([port])](#listen-port) but there are cases (like in tests) when it can be called explicitly.
|
||||
|
||||
## .teardown([server])
|
||||
|
||||
`app.teardown([server]) -> Promise<app>` can be called to gracefully shut down the application. When the app has been set up with a server (e.g. by calling `app.listen()`) the server will be closed automatically when calling `app.teardown()`. You can also register [application hooks](./hooks.md#application-hooks) on teardown to e.g. close database connection etc.
|
||||
`app.teardown([server]) -> Promise<app>` can be called to gracefully shut down the application. When the app has been set up with a server (e.g. by calling `app.listen()`) the server will be closed automatically when calling `app.teardown()`. You can also register [application hooks](./hooks.md#setup-and-teardown) on teardown to e.g. close database connection etc.
|
||||
|
||||
## .listen(port)
|
||||
|
||||
@ -169,7 +192,7 @@ Normally `app.setup` will be called automatically when starting the application
|
||||
|
||||
<BlockQuote type="danger">
|
||||
|
||||
`app.set` is global to the application. Do not use it for storing request or service method specific data. This can be done by adding data to the [hook context](./hooks.md#hook-context).
|
||||
`app.set` is global to the application. It is used for storing application wide information like database connection strings etc. **Do not use it for storing request or service specific data.** This can be done by adding data to the [hook context](./hooks.md#hook-context).
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
@ -194,7 +217,7 @@ app.listen(app.get('port'))
|
||||
|
||||
<BlockQuote type="info" label="Note">
|
||||
|
||||
On the server, settings are usually initialized using [@feathersjs/configuration](configuration.md).
|
||||
On the server, settings are usually initialized using [Feathers configuration](configuration.md).
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
@ -207,26 +230,26 @@ On the server, settings are usually initialized using [@feathersjs/configuration
|
||||
Provided by the core [NodeJS EventEmitter .on](https://nodejs.org/api/events.html#events_emitter_on_eventname_listener). Registers a `listener` method (`function(data) {}`) for the given `eventname`.
|
||||
|
||||
```js
|
||||
app.on('login', user => console.log('Logged in', user));
|
||||
app.on('login', (user) => console.log('Logged in', user))
|
||||
```
|
||||
|
||||
## .emit(eventname, data)
|
||||
|
||||
Provided by the core [NodeJS EventEmitter .emit](https://nodejs.org/api/events.html#events_emitter_emit_eventname_args). Emits the event `eventname` to all event listeners.
|
||||
Provided by the core [NodeJS EventEmitter .emit](https://nodejs.org/api/events.html#events_emitter_emit_eventname_args).
|
||||
|
||||
```ts
|
||||
type Message = { message: string }
|
||||
type MyEventData = { message: string }
|
||||
|
||||
app.emit('myevent', {
|
||||
message: 'Something happened'
|
||||
});
|
||||
})
|
||||
|
||||
app.on('myevent', (data: Message) => console.log('myevent happened', data));
|
||||
app.on('myevent', (data: MyEventData) => console.log('myevent happened', data))
|
||||
```
|
||||
|
||||
<BlockQuote type="warning">
|
||||
<BlockQuote type="warning" label="Important">
|
||||
|
||||
`app` can not receive or send events to or from clients. A [custom service](services.md) should be used for that.
|
||||
`app` can not receive or send events to or from clients. A [custom service](./services.md) should be used for that.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
@ -243,7 +266,7 @@ import type { Id } from '@feathersjs/feathers'
|
||||
|
||||
// Mixins have to be added before registering any services
|
||||
app.mixins.push((service: any, path: string) => {
|
||||
service.sayHello = function() {
|
||||
service.sayHello = function () {
|
||||
return `Hello from service at '${path}'`
|
||||
}
|
||||
})
|
||||
@ -265,14 +288,14 @@ app.service('todos').sayHello()
|
||||
```ts
|
||||
const servicePaths = Object.keys(app.services)
|
||||
|
||||
servicePaths.forEach(path => {
|
||||
servicePaths.forEach((path) => {
|
||||
const service = app.service(path)
|
||||
})
|
||||
```
|
||||
|
||||
<BlockQuote type="danger">
|
||||
|
||||
To retrieve services, the [app.service(path)](#service-path) method should be used, not `app.services[path]` directly.
|
||||
To retrieve services use [app.service(path)](#service-path), not `app.services[path]` directly.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
@ -280,14 +303,16 @@ A Feathers [client](client.md) does not know anything about the server it is con
|
||||
|
||||
```ts
|
||||
class InfoService {
|
||||
async find () {
|
||||
constructor(public app: Application) {}
|
||||
|
||||
async find() {
|
||||
return {
|
||||
service: Object.keys(app.services)
|
||||
service: Object.keys(this.app.services)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.use('info', new InfoService())
|
||||
app.use('info', new InfoService(app))
|
||||
```
|
||||
|
||||
## .defaultService
|
||||
@ -299,20 +324,9 @@ import { MemoryService } from '@feathersjs/memory'
|
||||
|
||||
// For every `path` that doesn't have a service
|
||||
// Automatically return a new in-memory service
|
||||
app.defaultService = function(path: string) {
|
||||
app.defaultService = function (path: string) {
|
||||
return new MemoryService()
|
||||
}
|
||||
```
|
||||
|
||||
This is used by the [client transport adapters](./client.md) to automatically register client side services that talk to a Feathers server.
|
||||
|
||||
## .lookup
|
||||
|
||||
`app.lookup(path)` allows to look up a full path and will return the `data` (route parameters) and `service` on the server.
|
||||
|
||||
```ts
|
||||
const { data, service } = app.lookup('messages/4321');
|
||||
|
||||
// service -> app.service('messages')
|
||||
// data -> { __id: '4321' }
|
||||
```
|
||||
|
||||
@ -53,7 +53,6 @@ const validationErrors = new BadRequest({
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
## Feathers errors
|
||||
|
||||
The following error types, all of which are instances of `FeathersError`, are available:
|
||||
@ -77,7 +76,7 @@ The following error types, all of which are instances of `FeathersError`, are av
|
||||
|
||||
<BlockQuote type="tip">
|
||||
|
||||
All of the Feathers plugins will automatically emit the appropriate Feathers errors for you. For example, most of the database adapters will already send `Conflict` or `Unprocessable` errors on validation errors.
|
||||
All of the Feathers core modules and most plugins and database adapters automatically emit the appropriate Feathers errors for you. For example, most of the database adapters will already send `Conflict` or `Unprocessable` errors on validation errors.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
@ -90,7 +89,7 @@ Feathers errors contain the following fields:
|
||||
- `data` - An object containing anything you passed to a Feathers error except for the `errors` object and `message`.
|
||||
- `errors` - An object containing whatever was passed to a Feathers error inside `errors`. This is typically validation errors or if you want to group multiple errors together.
|
||||
|
||||
<BlockQuote type="warning">
|
||||
<BlockQuote type="warning" label="Important">
|
||||
|
||||
To convert a Feathers error back to an object call `error.toJSON()`. A normal `console.log` of a JavaScript Error object will not automatically show those additional properties described above (even though they can be accessed directly).
|
||||
|
||||
@ -98,7 +97,7 @@ To convert a Feathers error back to an object call `error.toJSON()`. A normal `c
|
||||
|
||||
## Custom errors
|
||||
|
||||
You can create custom errors by extending from the `FeathersError` class and calling its constructor with `(msg, name, code, className, data)`:
|
||||
You can create custom errors by extending from the `FeathersError` class and calling its constructor with `(message, name, code, className, data)`:
|
||||
|
||||
- `message` - The error message
|
||||
- `name` - The error name (e.g. `MyError`)
|
||||
@ -106,13 +105,12 @@ You can create custom errors by extending from the `FeathersError` class and cal
|
||||
- `className` - The full name of the error class (e.g. `my-error`)
|
||||
- `data` - Additional data to include in the error
|
||||
|
||||
|
||||
```ts
|
||||
import { FeathersError } from '@feathersjs/errors'
|
||||
|
||||
class UnsupportedMediaType extends FeathersError {
|
||||
constructor(message: string, data: any) {
|
||||
super(message, 'UnsupportedMediaType', 415, 'unsupported-media-type', data);
|
||||
super(message, 'UnsupportedMediaType', 415, 'unsupported-media-type', data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,24 +126,24 @@ It is important to make sure that errors get cleaned up before they go back to t
|
||||
Here is an example error handler you can add to app.hooks errors.
|
||||
|
||||
```js
|
||||
const errors = require("@feathersjs/errors");
|
||||
const errorHandler = ctx => {
|
||||
const errors = require('@feathersjs/errors')
|
||||
const errorHandler = (ctx) => {
|
||||
if (ctx.error) {
|
||||
const error = ctx.error;
|
||||
const error = ctx.error
|
||||
if (!error.code) {
|
||||
const newError = new errors.GeneralError("server error");
|
||||
ctx.error = newError;
|
||||
return ctx;
|
||||
const newError = new errors.GeneralError('server error')
|
||||
ctx.error = newError
|
||||
return ctx
|
||||
}
|
||||
if (error.code === 404 || process.env.NODE_ENV === "production") {
|
||||
error.stack = null;
|
||||
if (error.code === 404 || process.env.NODE_ENV === 'production') {
|
||||
error.stack = null
|
||||
}
|
||||
return ctx;
|
||||
return ctx
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
then add it as an [application level](./application.md#hookshooks) error hook
|
||||
then add it as an [application level](./application.md#hooks-hooks) error hook
|
||||
|
||||
```ts
|
||||
app.hooks({
|
||||
|
||||
@ -27,15 +27,13 @@ const messages = app.service('messages')
|
||||
messages.on('patched', (message: Message) => console.log('message patched', message))
|
||||
|
||||
// Only listen to an event once
|
||||
messsages.once('removed', (message: Message) =>
|
||||
console.log('First time a message has been removed', message)
|
||||
)
|
||||
messsages.once('removed', (message: Message) => console.log('First time a message has been removed', message))
|
||||
|
||||
// A reference to a handler
|
||||
const onCreatedListener = (message: Message) => console.log('New message created', message)
|
||||
|
||||
// Listen `created` with a handler reference
|
||||
messages.on('created', onCreatedListener);
|
||||
messages.on('created', onCreatedListener)
|
||||
|
||||
// Unbind the `created` event listener
|
||||
messages.removeListener('created', onCreatedListener)
|
||||
@ -48,11 +46,11 @@ messages.emit('customEvent', {
|
||||
|
||||
## Service Events
|
||||
|
||||
Any service automatically emits `created`, `updated`, `patched` and `removed` events when the respective service method returns successfully. This works on the client as well as on the server. When the client is using [Socket.io](socketio.md), events will be pushed automatically from the server to all connected clients. This is how Feathers does real-time.
|
||||
Any service automatically emits `created`, `updated`, `patched` and `removed` events when the respective service method returns successfully. This works on the client as well as on the server. Events are not fired until all [hooks](./hooks.md) have executed. When the client is using [Socket.io](socketio.md), events will be pushed automatically from the server to all connected clients. This is how Feathers does real-time.
|
||||
|
||||
<BlockQuote type="tip">
|
||||
|
||||
Events are not fired until all of your [hooks](./hooks.md) have executed.
|
||||
To disable sending of events e.g. when updating a large amount of data, set [context.event](./hooks.md#context-event) to `null` in a hook.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
@ -65,15 +63,17 @@ The `created` event will fire with the result data when a service `create` retur
|
||||
```ts
|
||||
import { feathers, type Params, type HookContext } from '@feathersjs/feathers'
|
||||
|
||||
const app = feathers()
|
||||
|
||||
type Message = { text: string }
|
||||
|
||||
app.use('messages', {
|
||||
async create(data: Message, params: Params) {
|
||||
class MessageService {
|
||||
async create(data: Message) {
|
||||
return data
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const app = feathers<{ messages: MessageService }>()
|
||||
|
||||
app.use('messages', new MessageService())
|
||||
|
||||
// Retrieve the wrapped service object which is also an EventEmitter
|
||||
const messages = app.service('messages')
|
||||
@ -90,23 +90,24 @@ messages.create({
|
||||
The `updated` and `patched` events will fire with the callback data when a service `update` or `patch` method calls back successfully.
|
||||
|
||||
```ts
|
||||
import { feathers, type Id, type Params, type HookContext } from '@feathersjs/feathers'
|
||||
|
||||
const app = feathers()
|
||||
import { feathers } from '@feathersjs/feathers'
|
||||
import type { Id, Params, HookContext } from '@feathersjs/feathers'
|
||||
|
||||
type Message = { text: string }
|
||||
|
||||
const app = feathers()
|
||||
|
||||
app.use('my/messages/', {
|
||||
class MessageService {
|
||||
async update(id: Id, data: Message) {
|
||||
return data
|
||||
},
|
||||
}
|
||||
|
||||
async patch(id: Id, data: Message) {
|
||||
return data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const app = feathers<{ messages: MessageService }>()
|
||||
|
||||
app.use('messages', new MessageService())
|
||||
|
||||
const messages = app.service('my/messages')
|
||||
|
||||
@ -127,27 +128,32 @@ messages.patch(0, {
|
||||
The `removed` event will fire with the callback data when a service `remove` calls back successfully.
|
||||
|
||||
```ts
|
||||
import { feathers, type Id, type Params, type HookContext } from '@feathersjs/feathers'
|
||||
import { feathers } from '@feathersjs/feathers'
|
||||
import type { Id, Params, HookContext } from '@feathersjs/feathers'
|
||||
|
||||
const app = feathers()
|
||||
type Message = { text: string }
|
||||
|
||||
app.use('messages', {
|
||||
class MessageService {
|
||||
async remove(id: Id, params: Params) {
|
||||
return { id }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const app = feathers<{ messages: MessageService }>()
|
||||
|
||||
app.use('messages', new MessageService())
|
||||
|
||||
const messages = app.service('messages')
|
||||
|
||||
messages.on('removed', (message: Message, context: HookContext) => console.log('removed', message))
|
||||
messages.remove(1);
|
||||
messages.remove(1)
|
||||
```
|
||||
|
||||
## Custom events
|
||||
|
||||
By default, real-time clients will only receive the [standard events](#service-events). However, it is possible to define a list of custom events when registering the service with [app.use](./application.md#usepath-service--options) that should also be sent to the client when `service.emit('customevent', data)` is called on the server. The `context` for custom events won't be a full hook context but just an object containing `{ app, service, path, result }`.
|
||||
By default, real-time clients will only receive the [standard events](#service-events). However, it is possible to define a list of custom events that should also be sent to the client when registering the service with [app.use](./application.md##use-path-service-options) when `service.emit('customevent', data)` is called on the server. The `context` for custom events won't be a full hook context but just an object containing `{ app, service, path, result }`.
|
||||
|
||||
<BlockQuote type="warning">
|
||||
<BlockQuote type="warning" label="important">
|
||||
|
||||
Custom events can only be sent from the server to the client, not the other way (client to server). A [custom service](./services.md) should be used for those cases.
|
||||
|
||||
@ -158,13 +164,13 @@ For example, a payment service that sends status events to the client while proc
|
||||
```ts
|
||||
class PaymentService {
|
||||
async create(data: any, params: Params) {
|
||||
const customer = await createStripeCustomer(params.user);
|
||||
this.emit('status', { status: 'created' });
|
||||
const customer = await createStripeCustomer(params.user)
|
||||
this.emit('status', { status: 'created' })
|
||||
|
||||
const payment = await createPayment(data);
|
||||
this.emit('status', { status: 'completed' });
|
||||
const payment = await createPayment(data)
|
||||
this.emit('status', { status: 'completed' })
|
||||
|
||||
return payment;
|
||||
return payment
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,36 +180,23 @@ app.use('payments', new PaymentService(), {
|
||||
})
|
||||
```
|
||||
|
||||
The [database adapters](./databases/common.md) also take a list of custom events as an [initialization option](./databases/common.md#serviceoptions):
|
||||
|
||||
```ts
|
||||
import { MongoDbService } from '@feathersjs/mongodb'
|
||||
|
||||
app.use('payments', new MongoDbService({
|
||||
events: [ 'status' ],
|
||||
Model
|
||||
}))
|
||||
```
|
||||
|
||||
Using `service.emit` custom events can also be sent in a hook:
|
||||
|
||||
```js
|
||||
app.service('payments').hooks({
|
||||
after: {
|
||||
create(context: HookContext) {
|
||||
context.service.emit('status', { status: 'completed' });
|
||||
context.service.emit('status', { status: 'completed' })
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
Custom events can be [published through channels](./channels.md#publishing) just like standard events and listened to it in a [Feathers client](./client.md) or [directly on the socket connection](./client/socketio.md#listening-to-events):
|
||||
|
||||
|
||||
```js
|
||||
client.service('payments').on('status', data => {});
|
||||
client.service('payments').on('status', (data) => {})
|
||||
|
||||
// or
|
||||
socket.on('payments status', data => {});
|
||||
socket.on('payments status', (data) => {})
|
||||
```
|
||||
|
||||
@ -4,18 +4,18 @@ outline: deep
|
||||
|
||||
# Hooks
|
||||
|
||||
Hooks are pluggable middleware functions that can be registered __around__, __before__, __after__ or on __error__(s) of a [service method](./services.md). Multiple hook functions can be chained to create complex work-flows. A hook is **transport independent**, which means it does not matter if it has been called internally on the server, through HTTP(S) (REST), websockets or any other transport Feathers supports. They are also service agnostic, meaning they can be used with **any** service regardless of whether they have a model or not.
|
||||
Hooks are pluggable middleware functions that can be registered **around**, **before**, **after** or on **error**(s) of a [service method](./services.md). Multiple hook functions can be chained to create complex work-flows. A hook is **transport independent**, which means it does not matter if it has been called internally on the server, through HTTP(S) (REST), websockets or any other transport Feathers supports. They are also service agnostic, meaning they can be used with **any** service regardless of whether they use a database or not.
|
||||
|
||||
Hooks are commonly used to handle things like permissions, validation, logging, [authentication](./authentication/hook.md), [data schemas and resolvers](./schema/index.md), sending notifications and more. This pattern keeps your application logic flexible, composable, and much easier to trace through and debug. For more information about the design patterns behind hooks see [this blog post](https://blog.feathersjs.com/api-service-composition-with-hooks-47af13aa6c01).
|
||||
Hooks are commonly used to handle things like permissions, validation, logging, [authentication](./authentication/hook.md), [data schemas and resolvers](./schema/index.md), sending notifications and more. This pattern keeps your application logic flexible, composable, and easier to trace through and debug. For more information about the design patterns behind hooks see [this blog post](https://blog.feathersjs.com/api-service-composition-with-hooks-47af13aa6c01).
|
||||
|
||||
## Quick Example
|
||||
|
||||
The following example logs the runtime of any service method on the `messages` service and adds `createdAt` property before saving the data to the database:
|
||||
|
||||
```ts
|
||||
import { feathers, type HookContext, type NextFunction } from '@feathersjs/feathers';
|
||||
import { feathers, type HookContext, type NextFunction } from '@feathersjs/feathers'
|
||||
|
||||
const app = feathers();
|
||||
const app = feathers()
|
||||
|
||||
app.service('messages').hooks({
|
||||
around: {
|
||||
@ -44,6 +44,11 @@ app.service('messages').hooks({
|
||||
})
|
||||
```
|
||||
|
||||
<BlockQuote type="info">
|
||||
|
||||
While it is always possible to add properties like `createdAt` in the above example via hooks, the preferred way to make data modifications like this in Feathers 5 is via [schemas and resolvers](./schema/index.md).
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
## Hook functions
|
||||
|
||||
@ -51,15 +56,16 @@ app.service('messages').hooks({
|
||||
|
||||
`before`, `after` and `error` hook functions are functions that are `async` or return a promise and take the [hook context](#hook-context) as the parameter and return nothing or throw an error.
|
||||
|
||||
```js
|
||||
const hookFunction = async (context) => {
|
||||
```ts
|
||||
import { HookContext } from '../declarations'
|
||||
|
||||
export const hookFunction = async (context: HookContext) => {
|
||||
// Do things here
|
||||
}
|
||||
```
|
||||
|
||||
For more information see the [hook flow](#hook-flow) section.
|
||||
|
||||
|
||||
### around
|
||||
|
||||
`around` hooks are a special kind of hook that allow to control the entire `before`, `after` and `error` flow in a single function. They are a Feathers specific version of the generic [@feathersjs/hooks](https://github.com/feathersjs/hooks). An `around` hook is an `async` function that accepts two arguments:
|
||||
@ -70,10 +76,12 @@ For more information see the [hook flow](#hook-flow) section.
|
||||
In its simplest form, an around hook looks like this:
|
||||
|
||||
```js
|
||||
const myAsyncHook = async (context, next) => {
|
||||
import { HookContext, NextFunction } from '../declarations'
|
||||
|
||||
export const myAfoundHook = async (context: HookContext, next: NextFunction) => {
|
||||
try {
|
||||
// Code before `await next()` runs before the main function
|
||||
await next();
|
||||
await next()
|
||||
// Code after `await next()` runs after the main function.
|
||||
} catch (error) {
|
||||
// Do things on error
|
||||
@ -83,11 +91,11 @@ const myAsyncHook = async (context, next) => {
|
||||
}
|
||||
```
|
||||
|
||||
Any around hook can be wrapped around another function. Calling `await next()` will either call the next hook in the chain or the original function if all hooks have run.
|
||||
Any around hook can be wrapped around another function. Calling `await next()` will either call the next hook in the chain or the service method if all other hooks have run.
|
||||
|
||||
## Hook flow
|
||||
|
||||
In general, hooks are executed in the order [they are registered](#registering-hooks) with `around` hooks running first. Hooks are executed in the following order:
|
||||
In general, hooks are executed in the order [they are registered](#registering-hooks) with `around` hooks running first:
|
||||
|
||||
- `around` hooks (before `await next()`)
|
||||
- `before` hooks
|
||||
@ -95,7 +103,7 @@ In general, hooks are executed in the order [they are registered](#registering-h
|
||||
- `after` hooks
|
||||
- `around` hooks (after `await next()`)
|
||||
|
||||
Note that since `around` hooks wrap **around** everything, the first hook to run will be the last to execute it's code after `await next()`. This is reverse of the order `after` hooks execute.
|
||||
Note that since `around` hooks wrap **around** everything, the first hook to run will be the last to execute its code after `await next()`. This is reverse of the order `after` hooks execute.
|
||||
|
||||
The hook flow can be affected as follows.
|
||||
|
||||
@ -105,18 +113,18 @@ When an error is thrown (or the promise is rejected), all subsequent hooks - and
|
||||
|
||||
The following example throws an error when the text for creating a new message is empty. You can also create very similar hooks to use your Node validation library of choice.
|
||||
|
||||
```js
|
||||
```ts
|
||||
app.service('messages').hooks({
|
||||
before: {
|
||||
create: [
|
||||
context => {
|
||||
if(context.data.text.trim() === '') {
|
||||
throw new Error('Message text can not be empty');
|
||||
async (context: HookContext) => {
|
||||
if (context.data.text.trim() === '') {
|
||||
throw new Error('Message text can not be empty')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
### Setting `context.result`
|
||||
@ -127,19 +135,19 @@ When `context.result` is set in an `around` hook before calling `await next()` o
|
||||
app.service('users').hooks({
|
||||
before: {
|
||||
get: [
|
||||
(context: HookContext) => {
|
||||
async (context: HookContext) => {
|
||||
// Never call the actual users service
|
||||
// just use the authenticated user
|
||||
context.result = context.params.user;
|
||||
context.result = context.params.user
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
## Hook context
|
||||
|
||||
The hook `context` is passed to a hook function and contains information about the service method call. It has __read only__ properties that should not be modified and ___writeable___ properties that can be changed for subsequent hooks.
|
||||
The hook `context` is passed to a hook function and contains information about the service method call. It has **read only** properties that should not be modified and **_writeable_** properties that can be changed for subsequent hooks.
|
||||
|
||||
<BlockQuote type="tip">
|
||||
|
||||
@ -169,15 +177,15 @@ The `context` object is the same throughout a service method call so it is possi
|
||||
|
||||
### `context.params`
|
||||
|
||||
`context.params` is a __writeable__ property that contains the [service method](./services.md) parameters (including `params.query`). For more information see the [service params documentation](./services.md#params).
|
||||
`context.params` is a **writeable** property that contains the [service method](./services.md) parameters (including `params.query`). For more information see the [service params documentation](./services.md#params).
|
||||
|
||||
### `context.id`
|
||||
|
||||
`context.id` is a __writeable__ property and the `id` for a `get`, `remove`, `update` and `patch` service method call. For `remove`, `update` and `patch`, `context.id` can also be `null` when modifying multiple entries. In all other cases it will be `undefined`.
|
||||
`context.id` is a **writeable** property and the `id` for a `get`, `remove`, `update` and `patch` service method call. For `remove`, `update` and `patch`, `context.id` can also be `null` when modifying multiple entries. In all other cases it will be `undefined`.
|
||||
|
||||
### `context.data`
|
||||
|
||||
`context.data` is a __writeable__ property containing the data of a `create`, `update` and `patch` service method call.
|
||||
`context.data` is a **writeable** property containing the data of a `create`, `update` and `patch` service method call.
|
||||
|
||||
<BlockQuote type="info">
|
||||
|
||||
@ -187,7 +195,7 @@ The `context` object is the same throughout a service method call so it is possi
|
||||
|
||||
### `context.error`
|
||||
|
||||
`context.error` is a __writeable__ property with the error object that was thrown in a failed method call. It can be modified to change the error that is returned at the end.
|
||||
`context.error` is a **writeable** property with the error object that was thrown in a failed method call. It can be modified to change the error that is returned at the end.
|
||||
|
||||
<BlockQuote type="info">
|
||||
|
||||
@ -197,7 +205,7 @@ The `context` object is the same throughout a service method call so it is possi
|
||||
|
||||
### `context.result`
|
||||
|
||||
`context.result` is a __writeable__ property containing the result of the successful service method call. It is only available in `after` hooks. `context.result` can also be set in
|
||||
`context.result` is a **writeable** property containing the result of the successful service method call. It is only available in `after` hooks. `context.result` can also be set in
|
||||
|
||||
- An `around` or `before` hook to skip the actual service method (database) call
|
||||
- An `error` hook to swallow the error and return a result instead
|
||||
@ -210,23 +218,23 @@ The `context` object is the same throughout a service method call so it is possi
|
||||
|
||||
### `context.dispatch`
|
||||
|
||||
`context.dispatch` is a __writeable, optional__ property and contains a "safe" version of the data that should be sent to any client. If `context.dispatch` has not been set `context.result` will be sent to the client instead.
|
||||
`context.dispatch` is a **writeable, optional** property and contains a "safe" version of the data that should be sent to any client. If `context.dispatch` has not been set `context.result` will be sent to the client instead. `context.dispatch` only affects the data sent through a Feathers Transport like [REST](./express.md) or [Socket.io](./socketio.md). An internal method call will still get the data set in `context.result`.
|
||||
|
||||
<BlockQuote type="info">
|
||||
<BlockQuote type="warning" label="Important">
|
||||
|
||||
`context.dispatch` only affects the data sent through a Feathers Transport like [REST](./express.md) or [Socket.io](./socketio.md). An internal method call will still get the data set in `context.result`.
|
||||
`context.dispatch` is used by the `schemaHooks.resolveDispatch` [resolver](./schema/resolvers.md). Use dispatch resolvers whenever possible to get safe representations external data.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
### `context.http`
|
||||
|
||||
`context.http` is a __writeable, optional__ property that allows customizing HTTP response specific properties. The following properties can be set:
|
||||
`context.http` is a **writeable, optional** property that allows customizing HTTP response specific properties. The following properties can be set:
|
||||
|
||||
- `context.http.status` - Sets the [HTTP status code](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) that should be returned. Usually the most appropriate status code will be picked automatically but there are cases where it needs to be customized.
|
||||
- `context.http.headers` - An object with additional HTTP response headers
|
||||
- `context.http.location` - Setting this property will trigger a redirect for HTTP requests.
|
||||
|
||||
<BlockQuote type="warning">
|
||||
<BlockQuote type="warning" label="Important">
|
||||
|
||||
Setting `context.http` properties will have no effect when using a websocket real-time connection.
|
||||
|
||||
@ -234,8 +242,7 @@ Setting `context.http` properties will have no effect when using a websocket rea
|
||||
|
||||
### `context.event`
|
||||
|
||||
`context.event` is a __writeable, optional__ property that allows service events to be skipped by setting it to `null`
|
||||
|
||||
`context.event` is a **writeable, optional** property that allows service events to be skipped by setting it to `null`
|
||||
|
||||
## Registering hooks
|
||||
|
||||
@ -254,12 +261,6 @@ Hook functions are registered on a service through the `app.service(<servicename
|
||||
}
|
||||
```
|
||||
|
||||
<BlockQuote type="warning">
|
||||
|
||||
Hooks will only be available for the standard service methods or methods passed as an option to [app.use](application.md#usepath-service--options). See the [documentation for @feathersjs/hooks](https://github.com/feathersjs/hooks) how to use hooks on other methods.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
This means usual hook registration looks like this:
|
||||
|
||||
```ts
|
||||
@ -273,7 +274,9 @@ app.service('servicename').hooks({
|
||||
await next()
|
||||
}
|
||||
],
|
||||
find: [ /* other hook functions here */ ],
|
||||
find: [
|
||||
/* other hook functions here */
|
||||
],
|
||||
get: [],
|
||||
create: [],
|
||||
update: [],
|
||||
@ -283,32 +286,31 @@ app.service('servicename').hooks({
|
||||
myCustomMethod: []
|
||||
},
|
||||
before: {
|
||||
all: [
|
||||
async (context: HookContext) => console.log('before all hook ran')
|
||||
all: [async (context: HookContext) => console.log('before all hook ran')],
|
||||
find: [
|
||||
/* other hook functions here */
|
||||
],
|
||||
find: [ /* other hook functions here */ ],
|
||||
get: [],
|
||||
get: []
|
||||
// ...etc
|
||||
},
|
||||
after: {
|
||||
find: [
|
||||
async (context: HookContext) => console.log('after find hook ran')
|
||||
]
|
||||
find: [async (context: HookContext) => console.log('after find hook ran')]
|
||||
},
|
||||
error: {
|
||||
}
|
||||
error: {}
|
||||
})
|
||||
```
|
||||
|
||||
<BlockQuote type="tip">
|
||||
<BlockQuote type="warning">
|
||||
|
||||
`app.service(<servicename>).hooks(hooks)` can be called multiple times and the hooks will be registered in that order. Normally all hooks should be registered at once however to see at a glance what the service is going to do.
|
||||
Hooks will only be available for the standard service methods or methods passed in `options.methods` to [app.use](application.md#usepath-service--options). See the [documentation for @feathersjs/hooks](https://github.com/feathersjs/hooks) how to use hooks on other methods.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
Since around hooks offer the same functionality as `before`, `after` and `error` hooks at the same time they can also be registered without a nested object:
|
||||
|
||||
```ts
|
||||
import { HookContext, NextFunction } from './declarations'
|
||||
|
||||
// Passing an array of around hooks that run for every method
|
||||
app.service('servicename').hooks([
|
||||
async (context: HookContext, next: NextFunction) => {
|
||||
@ -337,7 +339,7 @@ app.service('servicename').hooks({
|
||||
|
||||
### Service hooks
|
||||
|
||||
To add hooks to every service `app.hooks(hooks)` can be used. Application hooks are [registered in the same format as service hooks](#registering-hooks) and also work exactly the same. Note when application hooks will be executed however:
|
||||
To add hooks to every service `app.hooks(hooks)` can be used. Application hooks are [registered in the same format as service hooks](#registering-hooks) and also work exactly the same. Note when application hooks will be executed:
|
||||
|
||||
- `around` application hook will run around all other hooks
|
||||
- `before` application hooks will always run _before_ all service `before` hooks
|
||||
@ -346,17 +348,23 @@ To add hooks to every service `app.hooks(hooks)` can be used. Application hooks
|
||||
|
||||
Here is an example for a very useful application hook that logs every service method error with the service and method name as well as the error stack.
|
||||
|
||||
```js
|
||||
```ts
|
||||
import { HookContext } from './declarations'
|
||||
|
||||
app.hooks({
|
||||
error(context) {
|
||||
console.error(`Error in '${context.path}' service method '${context.method}'`, context.error.stack);
|
||||
error: {
|
||||
all: [
|
||||
async (context: HookContext) => {
|
||||
console.error(`Error in '${context.path}' service method '${context.method}'`, context.error.stack)
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
### Setup and teardown
|
||||
|
||||
A special kind of application hooks are `setup` and `teardown` hooks. They are around hooks that can be used to initialize database connections etc. and only run once when the application starts up or shuts down.
|
||||
A special kind of application hooks are [app.setup](./application.md#setupserver) and [app.teardown](./application.md#teardownserver) hooks. They are around hooks that can be used to initialize database connections etc. and only run once when the application starts or shuts down. Setup and teardown hooks only have `context.app` and `context.server` available in the hook context.
|
||||
|
||||
```ts
|
||||
import { MongoClient } from 'mongodb'
|
||||
@ -364,16 +372,15 @@ import { MongoClient } from 'mongodb'
|
||||
app.hooks({
|
||||
setup: [
|
||||
async (context: HookContext, next: NextFunction) => {
|
||||
const mongodb = new MongoClient(yourConnectionURI)
|
||||
|
||||
await mongodb.connect()
|
||||
context.app.set('mongodb', mongodb)
|
||||
// E.g. wait for MongoDB connection to complete
|
||||
await context.app.get('mongoClient').connect()
|
||||
await next()
|
||||
}
|
||||
],
|
||||
teardown: [
|
||||
async (context: HookContext, next: NextFunction) => {
|
||||
context.app.get('mongodb').close()
|
||||
// Close MongoDB connection
|
||||
await context.app.get('mongoClient').close()
|
||||
await next()
|
||||
}
|
||||
]
|
||||
|
||||
@ -63,7 +63,6 @@ Methods are optional and if a method is not implemented Feathers will automatica
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
|
||||
Service methods must use [async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) or return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) and have the following parameters:
|
||||
|
||||
- `id` — The identifier for the resource. A resource is the data identified by a unique id.
|
||||
@ -88,9 +87,9 @@ Although probably the most common use case, a service does not necessarily have
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
<BlockQuote type="warning">
|
||||
<BlockQuote type="warning" label="Important">
|
||||
|
||||
This section describes the general usage of service methods and how to implement them. They are already implemented by the official Feathers database adapters. For specifics on how to use the database adapters, see the [database adapters common API](./databases/common.md).
|
||||
This section describes the general usage of service methods and how to implement them. They are already implemented by the official Feathers database adapters. For specifics on how to use the database adapters, see the [database adapters documentation](./databases/common.md).
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
@ -105,7 +104,7 @@ This section describes the general usage of service methods and how to implement
|
||||
- `params.connection` - If the service call has been made by a real-time transport (e.g. through websockets), `params.connection` is the connection object that can be used with [channels](./channels.md).
|
||||
- `params.headers` - The HTTP headers connected to this service call if available. This is either the headers of the REST call or the headers passed when initializing a websocket connection.
|
||||
|
||||
<BlockQuote type="warning">
|
||||
<BlockQuote type="warning" label="Important">
|
||||
|
||||
For external calls only `params.query` will be sent between the client and server. This is because other parameters in `params` on the server often contain security critical information (like `params.user` or `params.authentication`).
|
||||
|
||||
@ -117,14 +116,17 @@ For external calls only `params.query` will be sent between the client and serve
|
||||
|
||||
```ts
|
||||
class MessageService {
|
||||
async find (params: Params) {
|
||||
return [{
|
||||
id: 1,
|
||||
text: 'Message 1'
|
||||
}, {
|
||||
id: 2,
|
||||
text: 'Message 2'
|
||||
}]
|
||||
async find(params: Params) {
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
text: 'Message 1'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
text: 'Message 2'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +147,7 @@ app.use('messages', new MessageService())
|
||||
import type { Id, Params } from '@feathersjs/feathers'
|
||||
|
||||
class TodoService {
|
||||
async get (id: Id, params: Params) {
|
||||
async get(id: Id, params: Params) {
|
||||
return {
|
||||
id,
|
||||
text: `You have to do ${id}!`
|
||||
@ -156,7 +158,6 @@ class TodoService {
|
||||
app.use('todos', new TodoService())
|
||||
```
|
||||
|
||||
|
||||
### .create(data, params)
|
||||
|
||||
`service.create(data, params) -> Promise` - Creates a new resource with `data`. The method should return with the newly created data. `data` may also be an array.
|
||||
@ -171,7 +172,7 @@ type Message = { text: string }
|
||||
class MessageService {
|
||||
messages: Message[] = []
|
||||
|
||||
async create (data: Message, params: Params) {
|
||||
async create(data: Message, params: Params) {
|
||||
this.messages.push(data)
|
||||
|
||||
return data
|
||||
@ -181,18 +182,17 @@ class MessageService {
|
||||
app.use('messages', new MessageService())
|
||||
```
|
||||
|
||||
<BlockQuote type="warning">
|
||||
<BlockQuote type="warning" label="Important">
|
||||
|
||||
Note that `data` may also be an array. When using a [database adapters](./databases/adapters.md) the [`multi` option](./databases/common.md) has to be set to allow arrays.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
|
||||
### .update(id, data, params)
|
||||
|
||||
`service.update(id, data, params) -> Promise` - Replaces the resource identified by `id` with `data`. The method should return with the complete, updated resource data. `id` can also be `null` when updating multiple records, with `params.query` containing the query criteria.
|
||||
`service.update(id, data, params) -> Promise` - Replaces the resource identified by `id` with `data`. The method should return with the complete, updated resource data. `id` can also be `null` when updating multiple records.
|
||||
|
||||
A successful `update` method call emits the [`updated` service event](./events.md#updated-patched) with the returned data or a separate event for every item if the returned data is an array.
|
||||
A successful `update` method call emits the [`updated` service event](./events.md#updated-patched). If an array is returned, it will send an individual `updated` event for every item.
|
||||
|
||||
<BlockQuote type="info">
|
||||
|
||||
@ -204,7 +204,7 @@ The [database adapters](./databases/adapters.md) do not support completely repla
|
||||
|
||||
`patch(id, data, params) -> Promise` - Merges the existing data of the resource identified by `id` with the new `data`. `id` can also be `null` indicating that multiple resources should be patched with `params.query` containing the query criteria.
|
||||
|
||||
A successful `patch` method call emits the [`patched` service event](./events.md#updated-patched) with the returned data or a separate event for every item if the returned data is an array.
|
||||
A successful `patch` method call emits the [`patched` service event](./events.md#updated-patched) with the returned data. When an array is returned when patching mutiple items, it will send an individual `patched` event for every item in the array.
|
||||
|
||||
The method should return with the complete, updated resource data. Implement `patch` additionally (or instead of) `update` if you want to distinguish between partial and full updates and support the `PATCH` HTTP method.
|
||||
|
||||
@ -226,7 +226,6 @@ With [database adapters](./databases/adapters.md) the [`multi` option](./databas
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
|
||||
### .setup(app, path)
|
||||
|
||||
`service.setup(app, path) -> Promise` is a special method that initializes the service, passing an instance of the Feathers application and the path it has been registered on.
|
||||
@ -235,14 +234,13 @@ When calling [app.listen](application.md#listenport) or [app.setup](application.
|
||||
|
||||
### .teardown(app, path)
|
||||
|
||||
`service.teardown(app, path) -> Promise` is a special method that shuts down the service, passing an instance of the Feathers application and the path it has been registered on. If a service implements a `teardown` method, it will be called during [app.teardown()](application.md#teardownserver).
|
||||
|
||||
`service.teardown(app, path) -> Promise` is a special method that shuts down the service, passing an instance of the Feathers application and the path it has been registered on. If a service implements a `teardown` method, it will be called during [app.teardown()](application.md#teardownserver) or when unregistering the service via [app.unuse](./application.md#unusepath).
|
||||
|
||||
## Custom Methods
|
||||
|
||||
A custom method is any other service method you want to expose publicly. A custom method always has a signature of `(data, params)` with the same semantics as standard service methods (`data` is the payload, `params` is the service [params](#params)). They can be used with [hooks](./hooks.md) (including authentication) and must be `async` or return a Promise.
|
||||
A custom method is any other service method you want to expose publicly. A custom method **must have** the signature of `(data, params)` with the same semantics as standard service methods (`data` is the payload, `params` is the service [params](#params)). They can be used with [hooks](./hooks.md) (including authentication) and must be `async` or return a Promise.
|
||||
|
||||
In order to register a public custom method, the names of *all methods* have to be passed as the `methods` option when registering the service with [app.use()](./application.md#usepath-service--options)
|
||||
In order to register a public custom method, the names of _all methods_ have to be passed as the `methods` option when registering the service with [app.use()](./application.md#usepath-service--options)
|
||||
|
||||
```ts
|
||||
import type { Id, Params } from '@feathersjs/feathers'
|
||||
@ -259,7 +257,7 @@ class MyService {
|
||||
}
|
||||
}
|
||||
|
||||
async myCustomMethod (data: CustomData, params: Params) {
|
||||
async myCustomMethod(data: CustomData, params: Params) {
|
||||
return data
|
||||
}
|
||||
}
|
||||
@ -278,9 +276,9 @@ const app = feathers<ServiceTypes>()
|
||||
|
||||
See the [REST client](./client/rest.md) and [Socket.io client](./client/socketio.md) chapters on how to use those custom methods on the client.
|
||||
|
||||
<BlockQuote type="warning">
|
||||
<BlockQuote type="warning" label="Important">
|
||||
|
||||
When passing the `methods` option __all methods__ you want to expose, including standard service methods, must be listed. This allows to completely disable standard service method you might not want to expose. The `methods` option only applies to external access (via a transport like HTTP or websockets). All methods continue to be available internally on the server.
|
||||
When passing the `methods` option **all methods** you want to expose, including standard service methods, must be listed. This allows to completely disable standard service method you might not want to expose. The `methods` option only applies to external access (via a transport like HTTP or websockets). All methods continue to be available internally on the server.
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
@ -288,17 +286,14 @@ When passing the `methods` option __all methods__ you want to expose, including
|
||||
|
||||
When registering a service, Feathers (or its plugins) can also add its own methods to a service. Most notably, every service will automatically become an instance of a [NodeJS EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter).
|
||||
|
||||
|
||||
### .hooks(hooks)
|
||||
|
||||
Register [hooks](./hooks.md) for this service.
|
||||
|
||||
|
||||
### .publish([event, ] publisher)
|
||||
|
||||
Register an event publishing callback. For more information, see the [channels chapter](./channels.md).
|
||||
|
||||
|
||||
### .on(eventname, listener)
|
||||
|
||||
Provided by the core [NodeJS EventEmitter .on](https://nodejs.org/api/events.html#events_emitter_on_eventname_listener). Registers a `listener` method (`function(data) {}`) for the given `eventname`.
|
||||
@ -309,12 +304,10 @@ For more information about service events, see the [Events chapter](./events.md)
|
||||
|
||||
</BlockQuote>
|
||||
|
||||
|
||||
### .emit(eventname, data)
|
||||
|
||||
Provided by the core [NodeJS EventEmitter .emit](https://nodejs.org/api/events.html#events_emitter_emit_eventname_args). Emits the event `eventname` to all event listeners.
|
||||
|
||||
### .removeListener(eventname)
|
||||
|
||||
|
||||
Provided by the core [NodeJS EventEmitter .removeListener](https://nodejs.org/api/events.html#events_emitter_removelistener_eventname_listener). Removes all listeners, or the given listener, for `eventname`.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user