feathersjs/feathers

View on GitHub
docs/guides/basics/starting.md

Summary

Maintainability
Test Coverage
---
outline: deep
---

# Quick start

Alright then! Let's learn Feathers. In this quick start guide we'll create our first Feathers app, an API server and a simple website to use it. You'll see how easy it is to get started with Feathers in just a single file without additional boilerplate or tooling. If you want to jump right into creating a complete application you can go to the [Creating An App](./generator.md) chapter.

<img style="margin: 2em;" src="/img/main-character-bench.svg" alt="Getting started">

Feathers works with all [currently active NodeJS releases](https://github.com/nodejs/Release#release-schedule). All guides are assuming the languages features from the most current stable NodeJS release which you can get from the [NodeJS website](https://nodejs.org/en/).

<BlockQuote type="tip">

You can follow this guide on your own computer in the terminal or try the steps out live without installing anything in the [Feathers Quick Start on Stackblitz](https://stackblitz.com/@daffl/collections/feathers-quick-start).

</BlockQuote>

After successful installation, the `node` and `npm` commands should be available on the terminal:

```
node --version
```

```
npm --version
```

<BlockQuote type="warning" label="Important">

Running NodeJS and npm should not require admin or root privileges.

</BlockQuote>

Let's create a new folder for our application:

```sh
mkdir feathers-basics
cd feathers-basics
```

Since any Feathers application is a Node application, we can create a default [package.json](https://docs.npmjs.com/files/package.json) using `npm`:

<LanguageBlock global-id="ts">

```sh
npm init --yes
# Install TypeScript and its NodeJS wrapper
npm i typescript ts-node @types/node --save-dev
# Also initialize a TS configuration file that uses modern JavaScript
npx tsc --init --target es2020
```

</LanguageBlock>

<LanguageBlock global-id="js">

```sh
npm init --yes
```

</LanguageBlock>

## Installing Feathers

Feathers can be installed like any other Node module by installing the [@feathersjs/feathers](https://www.npmjs.com/package/@feathersjs/feathers) package through [npm](https://www.npmjs.com). The same package can also be used with module loaders like Vite, Webpack, and in React Native.

```sh
npm install @feathersjs/feathers --save
```

<BlockQuote label="note">

All Feathers core modules are in the `@feathersjs` namespace.

</BlockQuote>

## Our first app

Now we can create a Feathers application with a simple `messages` service that allows us to create new messages and find all existing ones.

<LanguageBlock global-id="ts">

Create a file called `app.ts` with the following content:

</LanguageBlock>
<LanguageBlock global-id="js">

Create a file called `app.mjs` with the following content:

</LanguageBlock>

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

// This is the interface for the message data
interface Message {
  id?: number
  text: string
}

// A messages service that allows us to create new
// and return all existing messages
class MessageService {
  messages: Message[] = []

  async find() {
    // Just return all our messages
    return this.messages
  }

  async create(data: Pick<Message, 'text'>) {
    // The new message is the data text with a unique identifier added
    // using the messages length since it changes whenever we add one
    const message: Message = {
      id: this.messages.length,
      text: data.text
    }

    // Add new message to the list
    this.messages.push(message)

    return message
  }
}

// This tells TypeScript what services we are registering
type ServiceTypes = {
  messages: MessageService
}

const app = feathers<ServiceTypes>()

// Register the message service on the Feathers application
app.use('messages', new MessageService())

// Log every time a new message has been created
app.service('messages').on('created', (message: Message) => {
  console.log('A new message has been created', message)
})

// A function that creates messages and then logs
// all existing messages on the service
const main = async () => {
  // Create a new message on our message service
  await app.service('messages').create({
    text: 'Hello Feathers'
  })

  // And another one
  await app.service('messages').create({
    text: 'Hello again'
  })

  // Find all existing messages
  const messages = await app.service('messages').find()

  console.log('All messages', messages)
}

main()
```

<LanguageBlock global-id="ts">

We can run it with

```sh
npx ts-node app.ts
```

</LanguageBlock>
<LanguageBlock global-id="js">

We can run it with

```sh
node app.mjs
```

</LanguageBlock>

[Try it out live >](https://stackblitz.com/edit/node-mupbmh?embed=1&file=app.ts&view=editor)

We will see something like this in the terminal:

```sh
A new message has been created { id: 0, text: 'Hello Feathers' }
A new message has been created { id: 1, text: 'Hello again' }
All messages [ { id: 0, text: 'Hello Feathers' },
  { id: 1, text: 'Hello again' } ]
```

Here we implemented only `find` and `create`, but a service can also have a few other methods, specifically `get`, `update`, `patch` and `remove`. We will learn more about service methods and events throughout this guide, but this sums up some of the most important concepts upon which Feathers is built.

## An API Server

So far we've created a Feathers application, a message service, and are listening to events. However, this is only a simple NodeJS script that prints some output and then exits. What we really want is to host it as an API server. This is where Feathers transports come in.

A transport takes a service like the one we created above and turns it into a server that other clients can talk to, like a website or mobile application.

In the following example we will take our existing service and use:

- `@feathersjs/koa` which uses [KoaJS](https://koajs.com/) to automatically turn our services into a REST API
- `@feathersjs/socketio` which uses Socket.io to do the same as a WebSocket, real-time API (as we will see in a bit this is where the `created` event we saw above comes in handy).

Run:

<LanguageBlock global-id="ts">

```sh
npm install @feathersjs/socketio @feathersjs/koa --save
```

Then update `app.ts` with the following content:

</LanguageBlock>
<LanguageBlock global-id="js">

```sh
npm install @feathersjs/socketio @feathersjs/koa koa-static --save
```

Then update `app.mjs` with the following content:

</LanguageBlock>

```ts{2-4,42-55,58-65}
import { feathers } from '@feathersjs/feathers'
import { koa, rest, bodyParser, errorHandler, serveStatic } from '@feathersjs/koa'
import socketio from '@feathersjs/socketio'

// This is the interface for the message data
interface Message {
  id?: number
  text: string
}

// A messages service that allows us to create new
// and return all existing messages
class MessageService {
  messages: Message[] = []

  async find() {
    // Just return all our messages
    return this.messages
  }

  async create(data: Pick<Message, 'text'>) {
    // The new message is the data text with a unique identifier added
    // using the messages length since it changes whenever we add one
    const message: Message = {
      id: this.messages.length,
      text: data.text
    }

    // Add new message to the list
    this.messages.push(message)

    return message
  }
}

// This tells TypeScript what services we are registering
type ServiceTypes = {
  messages: MessageService
}

// Creates an KoaJS compatible Feathers application
const app = koa<ServiceTypes>(feathers())

// Use the current folder for static file hosting
app.use(serveStatic('.'))
// Register the error handle
app.use(errorHandler())
// Parse JSON request bodies
app.use(bodyParser())

// Register REST service handler
app.configure(rest())
// Configure Socket.io real-time APIs
app.configure(socketio())
// Register our messages service
app.use('messages', new MessageService())

// Add any new real-time connection to the `everybody` channel
app.on('connection', (connection) => app.channel('everybody').join(connection))
// Publish all events to the `everybody` channel
app.publish((_data) => app.channel('everybody'))

// Start the server
app
  .listen(3030)
  .then(() => console.log('Feathers server listening on localhost:3030'))

// For good measure let's create a message
// So our API doesn't look so empty
app.service('messages').create({
  text: 'Hello world from the server'
})
```

[Try it out live >](https://stackblitz.com/edit/node-zfinli?embed=1&file=app.ts)

<LanguageBlock global-id="ts">

We can start the server with

```sh
npx ts-node app.ts
```

</LanguageBlock>
<LanguageBlock  global-id="js">

We can start the server with

```sh
node app.mjs
```

</LanguageBlock>

<BlockQuote type="info">

The server will stay running until you stop it by pressing **Control + C** in the terminal.

</BlockQuote>

And in the browser visit

```
http://localhost:3030/messages
```

to see an array with the one message we created on the server.

<BlockQuote>

The built-in [JSON viewer in Firefox](https://developer.mozilla.org/en-US/docs/Tools/JSON_viewer) or a browser plugin like [JSON viewer for Chrome](https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh) makes it nicer to view JSON responses in the browser.

</BlockQuote>

This is the basic setup of a Feathers API server.

- The `app.use` calls probably look familiar if you have used something like Koa or Express before.
- `app.configure` calls set up the Feathers transport to host the API.
- `app.on('connection')` and `app.publish` are used to set up event channels, which send real-time events to the proper clients (everybody that is connected to our server in this case). You can learn [more about the channels API](../../api/channels.md) after finishing this guide.

## In the browser

Now we can look at one of the really cool features of Feathers: **It works the same in a web browser!** This means that we could take [our first app example](#our-first-app) from above and run it just the same in a website. Since we already have a server running, however, let's go a step further and create a Feathers app that talks to our `messages` service on the server using a real-time Socket.io connection.

In the same folder, add the following `index.html` page:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Feathers Example</title>
    <link href="https://cdn.jsdelivr.net/npm/daisyui@2.46.1/dist/full.css" rel="stylesheet" type="text/css" />
    <link
      href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2/dist/tailwind.min.css"
      rel="stylesheet"
      type="text/css"
    />
    <link rel="stylesheet" href="https://feathersjs.com/feathers-chat.css" />
  </head>
  <body data-theme="dracula">
    <main id="main" class="p-8">
      <h1 class="font-medium leading-tight text-5xl mt-0 mb-2">Welcome to Feathers</h1>

      <div class="form-control w-full py-2">
        <form class="input-group overflow-hidden" onsubmit="sendMessage(event)">
          <input name="message" id="message-text" type="text" class="input input-bordered w-full" />
          <button type="submit" class="btn">Send</button>
        </form>
      </div>
      <h2 class="pt-1 pb-2 text-lg">Messages</h2>
    </main>

    <script src="//unpkg.com/@feathersjs/client@^5.0.0/dist/feathers.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script type="text/javascript">
      // Set up socket.io
      const socket = io('http://localhost:3030')
      // Initialize a Feathers app
      const app = feathers()

      // Register socket.io to talk to our server
      app.configure(feathers.socketio(socket))

      // Form submission handler that sends a new message
      async function sendMessage(event) {
        const messageInput = document.getElementById('message-text')

        event.preventDefault()

        // Create a new message with the input field value
        await app.service('messages').create({
          text: messageInput.value
        })

        messageInput.value = ''
      }

      // Renders a single message on the page
      function addMessage(message) {
        document.getElementById('main').innerHTML += `<div class="chat chat-start">
          <div class="chat-bubble">${message.text}</div>
        </div>`
      }

      const main = async () => {
        // Find all existing messages
        const messages = await app.service('messages').find()

        // Add existing messages to the list
        messages.forEach(addMessage)

        // Add any newly created message to the list in real-time
        app.service('messages').on('created', addMessage)
      }

      main()
    </script>
  </body>
</html>
```

[Try it out live >](https://stackblitz.com/edit/node-m7cjfd?embed=1&file=index.html)

Now in the browser if you go to

```
http://localhost:3030
```

you will see a simple website that allows creating new messages. It is possible to open the page in two tabs and see new messages show up on either side in real-time. You can verify that the messages got created by visiting

```
http://localhost:3030/messages
```

You'll see the JSON response including all current messages.

## What's next?

In this chapter we created our first Feathers application and a service that allows creating new messages, storing them in memory, and retrieving them. We then hosted that service as a REST and real-time API server and used Feathers in the browser to connect to that server and create a website that can send new messages and show all existing messages in real-time.

Even though we are using just NodeJS and Feathers from scratch without any additional tools, we didn't write a lot of code. In the [next chapter](./generator.md) we will look at the Feathers CLI which can create a similar Feathers application with a recommended file structure, models, database connections, authentication and more.