Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
More documentation review
  • Loading branch information
daffl committed Mar 19, 2026
commit ca16d284d563c90d8d292b92b53cba054ece651b
49 changes: 26 additions & 23 deletions website/content/api/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
npm install feathers@pre --save
```

`import { feathers } from 'feathers` provides the ability to initialize a new Feathers application instance. It works on all runtimes, React Native and the browser (see the [client](./client) chapter for more information). Each instance allows for registration and retrieval of [services](./services), [hooks](./hooks), plugin configuration, and getting and setting configuration options. An initialized Feathers application is referred to as the **app object**.
`import { feathers } from 'feathers'` provides the ability to initialize a new Feathers application instance. It works on all runtimes, React Native and the browser (see the [client](./client) chapter for more information). Each instance allows for registration and retrieval of [services](./services), [hooks](./hooks), plugin configuration, and getting and setting configuration options. An initialized Feathers application is referred to as the **app object**.

```ts
import { feathers } from 'feathers'
Expand Down Expand Up @@ -63,7 +63,7 @@ The following options are available:
- `events` - A list of [public custom events sent by this service](./events#custom-events)

```ts
import { feathers, type Id, EventEmitter } from '@feathersjs/feathers'
import { feathers, type Id, type Params, EventEmitter } from 'feathers'

// Feathers services will always be event emitters
// but we can also extend it for better type consistency
Expand Down Expand Up @@ -115,27 +115,27 @@ const message = await messageService.get('test')
console.log(message)

messageService.on('created', (message: Message) => {
console.log('Created a todo')
console.log('Created a message')
})
```

::note[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)
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 parameters use [.lookup](#lookuppath)
::

## .lookup(path)

`app.lookup(path)` allows to look up a full path and will return the `data` (route parameters) and `service` **on the server**.
`app.lookup(path)` allows to look up a full path and will return the `params` (route parameters) and `service` **on the server**. Returns `null` if no service was found for the path.

```ts
const lookup = app.lookup('messages/4321')

// lookup.service -> app.service('messages')
// lookup.data -> { __id: '4321' }
// lookup.params -> { __id: '4321' }

// `lookup.dta` needs to be passed as `params.route`
// `lookup.params` needs to be passed as `params.route`
lookup.service.find({
route: lookup.data
route: lookup.params
})
```

Expand Down Expand Up @@ -167,20 +167,29 @@ app.configure(setupService)

## .setup([server])

`app.setup([server]) -> Promise<app>` is used to initialize all services by calling each [services .setup(app, path)](services#setupapp-path) method (if available).
It will also use the `server` instance passed (e.g. through `http.createServer`) to set up any provider that might require the server instance. You can register [application setup hooks](./hooks#setup-and-teardown) to e.g. set up database connections and other things required to be initialized on startup in a certain order.
`app.setup([server]) -> Promise<app>` is used to initialize all services by calling each [services .setup(app, path)](services#setupapp-path) method (if available). You can register [application setup hooks](./hooks#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.
```ts
import { createServer } from 'node:http'
import { feathers } from 'feathers'
import { createHandler } from 'feathers/http'
import { toNodeHandler } from 'feathers/http/node'

## .teardown([server])
const app = feathers()
// ... configure your app

`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#setup-and-teardown) on teardown to e.g. close database connection etc.
const handler = createHandler(app)
const server = createServer(toNodeHandler(handler))

## .listen(port)
server.listen(3030)

// Initialize all services and pass the server instance
await app.setup(server)
```

`app.listen([port]) -> Promise<HTTPServer>` starts the application on the given port. It will set up all configured transports (if any) and then run [app.setup(server)](#setup-server) with the server object and then return the server object.
## .teardown([server])

`listen` will only be available if a server side transport (HTTP) has been configured.
`app.teardown([server]) -> Promise<app>` can be called to gracefully shut down the application. You can register [application hooks](./hooks#setup-and-teardown) on teardown to e.g. close database connections etc.

## .set(name, value)

Expand All @@ -205,14 +214,8 @@ type Configuration = {
const app = feathers<ServiceTypes, Configuration>()

app.set('port', 3030)

app.listen(app.get('port'))
```

::note[Note]
On the server, settings are usually initialized using [Feathers configuration](configuration).
::

## .get(name)

`app.get(name) -> value` retrieves the setting `name`.
Expand Down Expand Up @@ -289,7 +292,7 @@ To retrieve services use [app.service(path)](#service-path), not `app.services[p

## .defaultService

`app.defaultService` can be a function that returns an instance of a new standard service for `app.service(path)` if there isn't one registered yet. By default it throws a `NotFound` error when you are trying to access a service that doesn't exist.
`app.defaultService` can be a function that returns an instance of a new standard service for `app.service(path)` if there isn't one registered yet. By default it throws an error when you are trying to access a service that doesn't exist.

```ts
import { MemoryService } from '@feathersjs/memory'
Expand Down
29 changes: 14 additions & 15 deletions website/content/api/errors.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Errors

`feathersjs/errors` contains a set of standard error classes used by all other Feathers modules.
`feathers/errors` contains a set of standard error classes used by all other Feathers modules.

## Examples

Expand Down Expand Up @@ -31,7 +31,7 @@ const validationErrors = new BadRequest('Invalid Parameters', {
})

// You can also omit the error message and we'll put in a default one for you
const validationErrors = new BadRequest({
const validationErrors2 = new BadRequest({
errors: {
email: 'Invalid Email'
}
Expand All @@ -51,6 +51,7 @@ The following error types, all of which are instances of `FeathersError`, are av
- 406: `NotAcceptable`
- 408: `Timeout`
- 409: `Conflict`
- 410: `Gone`
- 411: `LengthRequired`
- 422: `Unprocessable`
- 429: `TooManyRequests`
Expand Down Expand Up @@ -87,7 +88,7 @@ You can create custom errors by extending from the `FeathersError` class and cal
- `data` - Additional data to include in the error

```ts
import { FeathersError } from '@feathersjs/errors'
import { FeathersError } from 'feathers/errors'

class UnsupportedMediaType extends FeathersError {
constructor(message: string, data: any) {
Expand All @@ -102,35 +103,33 @@ console.log(error.toJSON())

## Error Handling

It is important to make sure that errors get cleaned up before they go back to the client. If you want to make sure that ws errors are handled as well, you need to use [application error hooks](hooks#application-hooks) which are called on any service call error.
It is important to make sure that errors get cleaned up before they go back to the client. You can use [application error hooks](hooks#application-hooks) which are called on any service call error.

Here is an example error handler you can add to app.hooks errors.

```js
import type { NextFunction, HookContext } from 'feathers'
```ts
import type { HookContext } from 'feathers'
import { GeneralError } from 'feathers/errors'

export const errorHandler = (ctx: HookContext) => {
if (ctx.error) {
const error = ctx.error
const errorHandler = async (context: HookContext) => {
if (context.error) {
const error = context.error
if (!error.code) {
const newError = new errors.GeneralError('server error')
ctx.error = newError
return ctx
context.error = new GeneralError('server error')
return context
}
if (error.code === 404 || process.env.NODE_ENV === 'production') {
error.stack = null
}
return ctx
return context
}
}
```

then add it as an [application level](./application#hooks-hooks) error hook
Then add it as an [application level](./application#hookshooks) error hook:

```ts
app.hooks({
//...
error: {
all: [errorHandler]
}
Expand Down
33 changes: 17 additions & 16 deletions website/content/api/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

# Events

Events are the key part of Feathers real-time functionality. All events in Feathers are provided through the [NodeJS EventEmitter](https://nodejs.org/api/events.html) interface. This section describes
Events are the key part of Feathers real-time functionality. All events in Feathers are provided through the [EventEmitter](https://nodejs.org/api/events.html) interface. This section describes

- A quick overview of the [NodeJS EventEmitter interface](#eventemitters)
- A quick overview of the [EventEmitter interface](#eventemitters)
- The standard [service events](#service-events)
- How to allow sending [custom events](#custom-events) from the server to the client

Expand All @@ -14,7 +14,7 @@ For more information on how to safely send real-time events to clients, see the

## EventEmitters

Once registered, any [service](./services) gets turned into a standard [NodeJS EventEmitter](https://nodejs.org/api/events.html) and can be used accordingly.
Once registered, any [service](./services) gets turned into a standard [EventEmitter](https://nodejs.org/api/events.html) and can be used accordingly.

```ts
const messages = app.service('messages')
Expand All @@ -23,7 +23,7 @@ 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))
messages.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)
Expand All @@ -45,7 +45,7 @@ messages.emit('customEvent', {
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) have executed. When the client is using [SSE](./client/sse), events will be pushed automatically from the server to all connected clients. This is how Feathers does real-time.

::tip
To disable sending of events e.g. when updating a large amount of data, set [context.event](./hooks#context-event) to `null` in a hook.
To disable sending of events e.g. when updating a large amount of data, set [context.event](./hooks#contextevent) to `null` in a hook.
::

Additionally to the event `data`, all events also get the [hook context](./hooks) from their method call passed as the second parameter.
Expand All @@ -55,7 +55,8 @@ Additionally to the event `data`, all events also get the [hook context](./hooks
The `created` event will fire with the result data when a service `create` returns successfully.

```ts
import { feathers, type Params, type HookContext } from '@feathersjs/feathers'
import { feathers } from 'feathers'
import type { HookContext } from 'feathers'

type Message = { text: string }

Expand All @@ -72,7 +73,7 @@ app.use('messages', new MessageService())
// Retrieve the wrapped service object which is also an EventEmitter
const messages = app.service('messages')

messages.on('created', (message: Message, contexHookContext) => console.log('created', message))
messages.on('created', (message: Message, context: HookContext) => console.log('created', message))

messages.create({
text: 'We have to do something!'
Expand All @@ -84,8 +85,8 @@ 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 } from '@feathersjs/feathers'
import type { Id, Params, HookContext } from '@feathersjs/feathers'
import { feathers } from 'feathers'
import type { Id, HookContext } from 'feathers'

type Message = { text: string }

Expand All @@ -103,7 +104,7 @@ const app = feathers<{ messages: MessageService }>()

app.use('messages', new MessageService())

const messages = app.service('my/messages')
const messages = app.service('messages')

messages.on('updated', (message: Message, context: HookContext) => console.log('updated', message))
messages.on('patched', (message: Message) => console.log('patched', message))
Expand All @@ -122,8 +123,8 @@ messages.patch(0, {
The `removed` event will fire with the callback data when a service `remove` calls back successfully.

```ts
import { feathers } from '@feathersjs/feathers'
import type { Id, Params, HookContext } from '@feathersjs/feathers'
import { feathers } from 'feathers'
import type { Id, Params, HookContext } from 'feathers'

type Message = { text: string }

Expand All @@ -145,9 +146,9 @@ 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 that should also be sent to the client when registering the service with [app.use](./application##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 }`.
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#usepath-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 }`.

::warning[important]
::warning[Important]
Custom events can only be sent from the server to the client, not the other way (client to server). A [custom service](./services) should be used for those cases.
::

Expand All @@ -174,7 +175,7 @@ app.use('payments', new PaymentService(), {

Using `service.emit` custom events can also be sent in a hook:

```js
```ts
app.service('payments').hooks({
after: {
create(context: HookContext) {
Expand All @@ -186,6 +187,6 @@ app.service('payments').hooks({

Custom events can be [published through channels](./channels#publishing) just like standard events and listened to in a [Feathers client](./client):

```js
```ts
client.service('payments').on('status', (data) => {})
```
Loading
Loading