# Quickstart: Node.js and Express
Source: https://sovaria.in/docs/quickstart-express

Build a notes API with Express that signs users in through Sovaria and runs every query as the calling user, so your row rules apply on the server too.

An Express API with `POST /signup`, `POST /signin`, `GET /notes` and `POST /notes`. It never holds a key that can bypass your rules: each request runs as the user whose token it carries.

## Before you start

Do steps 1 to 3 of the [Quickstart](https://sovaria.in/docs/quickstart) first: create a project, copy its **project URL** and **anon key** ([Quickstart](https://sovaria.in/docs/quickstart#connect)), and create the `notes` table with its row rules ([Quickstart](https://sovaria.in/docs/quickstart#table)). Every signed-in user then sees and changes only their own notes, whatever the app code does.

## 1. Create the project

Terminal:
```bash
mkdir notes-api && cd notes-api
npm init -y && npm pkg set type=module
npm install express @sovaria/sdk
```

.env:
```bash
SOVARIA_URL=https://<project-ref>.sovarias.in
SOVARIA_ANON_KEY=<anon-key>
```

## 2. The server

server.js:
```js
import express from 'express'
import { createClient, SovariaError } from '@sovaria/sdk'

const { SOVARIA_URL, SOVARIA_ANON_KEY } = process.env
const app = express()
app.use(express.json())

// A fresh client per request. persistSession: false keeps nothing between requests.
const anonymous = () => createClient(SOVARIA_URL, SOVARIA_ANON_KEY, { persistSession: false })
const asUser = (req) => {
  const token = req.get('authorization')?.replace(/^Bearer /, '')
  if (!token) throw Object.assign(new Error('Sign in first'), { statusCode: 401 })
  return anonymous().setAccessToken(token)
}
// data.sql answers { columns, rows, row_count }; rows are arrays in column order.
export const toObjects = ({ columns, rows }) =>
  rows.map((row) => Object.fromEntries(columns.map((c, i) => [c, row[i]])))

// Answers { access_token, refresh_token, expires_in, … }; the app keeps the tokens.
app.post('/signup', async (req, res, next) => {
  try { res.json(await anonymous().auth.signUp(req.body.email, req.body.password)) } catch (e) { next(e) }
})
app.post('/signin', async (req, res, next) => {
  try { res.json(await anonymous().auth.signIn(req.body.email, req.body.password)) } catch (e) { next(e) }
})

app.get('/notes', async (req, res, next) => {
  try { res.json(toObjects(await asUser(req).data.sql('select id, body, created_at from notes order by id desc'))) }
  catch (e) { next(e) }
})
app.post('/notes', async (req, res, next) => {
  try {
    const r = await asUser(req).data.sql('insert into notes (body) values ($1) returning id, body', [req.body.body])
    res.status(201).json(toObjects(r)[0])
  } catch (e) { next(e) }
})

app.use((err, _req, res, _next) => {
  const status = err.statusCode || 500
  res.status(status).json({ error: err instanceof SovariaError ? err.code : 'ERROR', message: err.message })
})

app.listen(3000, () => console.log('http://localhost:3000'))
```

## 3. Run and try it

Terminal:
```bash
node --env-file=.env server.js

# in another terminal
TOKEN=$(curl -s localhost:3000/signup -H 'Content-Type: application/json' \
  -d '{"email":"ada@example.com","password":"Correct-Horse-9!"}' | jq -r .access_token)
curl -s localhost:3000/notes -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"body":"From Express"}'
curl -s localhost:3000/notes -H "Authorization: Bearer $TOKEN"
```

- Server-to-server calls send no browser `Origin`, so allowed origins don't apply here.
- Need to act as your app rather than a user (a nightly job, a webhook)? Use the service role key from a secret store, on the server only. It bypasses every rule, so keep those code paths small ([API keys](https://sovaria.in/docs/api-keys)).
- To check a token without calling Sovaria, verify it against your project's JWKS ([Sessions and tokens](https://sovaria.in/docs/sessions-and-tokens)).

## Next steps

- Check who can read and change `notes` before you ship: [Tutorial: prove your table is private before you ship](https://sovaria.in/docs/tutorial-secure-a-table).
- Push new notes to other devices as they happen: [Database change events](https://sovaria.in/docs/realtime-database-changes).
- Every SDK method: [JavaScript SDK](https://sovaria.in/docs/javascript-reference).
- Run this code next to your data instead: [Functions](https://sovaria.in/docs/functions-overview).
