0.7.2 • Published 2 years ago

@mathio28/next-api v0.7.2

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

next-api

Test npm version

The "no api" api for Next.js apps.

Installation

yarn add @mathio28/next-api

Requirements

  • node >= 12
  • next.js >= 10

Usage

Server-side

Installing will automatically create file /pages/api/[collection].js with content:

import nextApi from 'next-api'
export default nextApi()

Specify connection string URL in env variable MONGODB_URL.

Client-side

Use helper methods to make requests to your API endpoints:

import { get, post, put, del } from '@mathio28/next-api/fetch'

await post('/api/auth', { email: 'user@example.com', pwd: 'password' }) // sign up
await put('/api/auth', { email: 'user@example.com', pwd: 'password' }) // login

const { _id } = await post('/api/card', { title: 'Hello!' }) // create new card
await put(`/api/card?id=${id}`, { title: 'Bye' }) // edit card (via query param)
await put('/api/card', { _id, title: 'Goodbye' }) // edit card (via _id in payload)
const cards = await get('/api/card') // get all cards
console.log(cards) // array of 1 object
await del(`/api/card?id=${_id}`) // delete card

await del('/api/auth') // logout

This works in browser as it takes care of cookies automatically. If you want to make API requests server-side you will need to use fetch and persist auth cookie manually (named "next-api-auth" by default).

Client-side with Typescript

The library is written in JavaScript but it provides typings. In a Typescript project you can provide an interface of the object to get type validation:

import { get, post } from '@mathio28/next-api/fetch'

interface Card {
  title: string
  text: string
}

const allCards = await get<Card[]>('/api/card')
allCards.forEach((card) => {
  card.title
  card.text
  card._id
  card.userId
  card.created
  card.updated // optional
  card.acl_read
  card.acl_write
  card.tag // TS2339: Property 'tag' does not exist on type 'Card'.
})

await post<Card>('/api/card', { title: 'bar', text: 'foo', tag: 1 })
// TS2345: Argument of type '{ title: string; text: string; tag: number; }' is not assignable to parameter of type 'Card'.
//   Object literal may only specify known properties, and 'tag' does not exist in type 'Card'.

Advanced usage

Config

You can pass config object to nextApi():

import nextApi from '@mathio28/next-api'
import { SECURITY } from 'next-api/config'

export default nextApi({
  mongoDbUrl: '<connection string URI>', // instead of MONGODB_URL env variable
  authCookieName: '<custom name>', // cookie name used for auth (defaults to "next-api-auth")
  security: SECURITY.USER_SANDBOX, // default security settings for database (0, 1, 2), defaults to 1 (SECURITY.USER_SANDBOX)
  sessionTime: 24 * 60 * 60 * 1000, // session expiry time in milliseconds (since last request), defaults to 1 day
})

Available settings for security (integer):

  • SECURITY.NONE (0) - no security, anyone can get, edit and delete all documents
  • SECURITY.USER_SANDBOX (1) - user can get, edit and delete only the documents they created
  • SECURITY.READ_ALL (2) - user can get all documents, but can edit and delete only documents they created

You can override those settings for each record you save by setting acl_read and acl_write as an array of user ids.

Side effects

You can supply 2 callbacks to execute custom logic for given route.

You can access the database via Database class provided as 3rd parameter.

import nextApi from '@mathio28/next-api'

export default nextApi(
  {},
  async (req, res, db) => {
    // executes BEFORE next-api logic

    // check current user
    console.log(db.user)

    // access database, the db object it takes care of correct permissions
    await db.find(collection, idOrQuery, sort)
    await db.save(collection, body, id)
    await db.remove(collection, id)

    return false // prevents execution of default next-api logic for this route
  },
  (req, res, db) => {
    // executes AFTER next-api logic
    return false // prevents default response
  }
)

If you want to execute side effects for specific route only, you can set it up in /api/my-route.js instead of /api/[collection].js.

API Docs

GET /api/<collection>

Returns array of all items from given collection.

Sort by sort query param, eg. ?sort=date ascending, ?sort=date:-1 descending. Default sort is created:-1 (newest first).

Filter by specifying additional query params, eg. ?age=18.

When ID query param is specified ?id=<objectId> it will return only the item, not an array.

POST /api/<collection>

Create a new item in given collection. Request body sent as JSON is saved.

If request body is array multiple objects will be created (one for each object in the array).

Returns created item(s).

PUT /api/<collection>

Update existing item in given collection. Request body sent as JSON is saved.

Specify the item ID as query param ?id=<objectId> or in body as _id.

Returns updated item.

DELETE /api/<collection>

Delete one item with specified ObjectID from given collection.

Specify the item ID as query param ?id=<objectId> or in body as _id. Send _id as array to delete multiple objects.

Returns number of deleted items.

Auth

  • POST /api/auth create new user (email and pwd required) or update current user if authorized
  • PUT /api/auth login with email and pwd in body (generate token and set cookie)
  • GET /api/auth get currently logged user (based on cookie)
  • DELETE /api/auth logout (delete token and cookie)

When you login a HTTP-only cookie will be created with auth token.

Singleton collections /api/one-<collection>

Collections starting with one- are considered singletons, eg. /api/one-config.

You dont need to specify id when retrieving or saving the item, it will always retrieve, create or update one item.

  • GET returns object, not array
  • PUT creates new or updates existing item
  • POST and DELETE are not allowed

Helper methods

To interact with the API you can use methods:

  • get('/api/<collection>')
  • post('/api/<collection>', { ...data })
  • put('/api/<collection>', { ...data })
  • del('/api/<collection>')
0.7.2

2 years ago

0.7.1

2 years ago

0.5.0

2 years ago

0.4.0

2 years ago

0.7.0

2 years ago

0.6.0

2 years ago

0.3.0

3 years ago

0.2.0

3 years ago

0.1.1

3 years ago

0.0.1

3 years ago

0.1.0

3 years ago

1.4.0

3 years ago

1.3.0

3 years ago

1.2.0

3 years ago

1.0.0

3 years ago