1.0.16 • Published 5 months ago

mongo-hono v1.0.16

Weekly downloads
-
License
ISC
Repository
-
Last release
5 months ago

Mongo Hono

This simple framework is based on Hono and Mongoose.

For the time being, you can only use JavaScript.

Please install hono and mongoose before use, and since this framework uses Node.js, please install @hono/node-server at the same time.

npm install hono @hono/node-server mongoose

If you want to create a websocket app, please install @hono/node-ws.

npm install @hono/node-ws

NOTE: It's alpha now!!!

Last Update

  • Methods
    • createApp (modified)
  • App Methods:
    • createWebScoket (deleted)

Methods

IndexNameFrom
1createAppmongo-hono
2createRoutermongo-hono
3useRoutermongo-hono
4connectDBmongo-hono
5createSchemamongo-hono
6createModelmongo-hono
7setRequiredErrorMessagemongo-hono
8setMinlengthErrorMessagemongo-hono
9setMaxlengthErrorMessagemongo-hono
10setMinErrorMessagemongo-hono
11setMaxErrorMessagemongo-hono
12setEnumErrorMessagemongo-hono
13setUniqueErrorMessagemongo-hono
14setUserDefinedErrorMessagemongo-hono
15errorHandlermongo-hono
16getHttpErrorCodemongo-hono
17getHttpStatusmongo-hono
18useWebSocketmongo-hono

App Methods

IndexNameParameter Type
1useMiddlewarearray
2useRoutersarray
3useCors
4useStaticstring
5listennumber

WebSocket Methods

IndexName
1upgradeWebSocket
2create
3deleteOne
4deleteAll
5broadcast
6getLength

Basic Example

Folder

  • src
    • apples
      • apples.model.js
      • apples.router.js
    • bananas
      • bananas.model.js
      • bananas.router.js
    • index.js
    • router.js
  • static
    • index.html

~/src/index.js

import { createApp, connectDB, errorHandler } from 'mongo-hono'
import routers from './routers.js'

await connectDB('mongodb://127.0.0.1:27017/test')
console.log('MongoDB is connected')

const app = await createApp()

app
  .useCors()
  .useStatic('/static')
  .useRouters(routers)
  .onError(errorHandler)
  .listen(3000)

console.log('Server is running on http://localhost:3000')

~/src/routers.js

import applesRouter from './apples/apples.router.js'
import bananasRouter from './bananas/bananas.router.js'

const routers = [
  applesRouter,
  bananasRouter
]

export default routers

~/static/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>
<body>
  <h3>Static</h3>
</body>
</html>

~/src/apples/apples.model.js

const apples = [
  {
    id: 1,
    name: 'apple #1'
  },
  {
    id: 2,
    name: 'apple #2'
  },
  {
    id: 3,
    name: 'apple #3'
  }
]

const Apple = {
  find() {
    return apples
  },
  findById(id) {
    return apples.find((apple) => apple.id == id)
  }
}

export default Apple

~/src/apples/apples.router.js

import { createRouter } from 'mongo-hono'
import Apple from './apples.model.js'

const applesRouter = createRouter('/apples')

const { on } = applesRouter

on('GET', '/', async function ({ jsend }) {
  const apples = Apple.find()
  return jsend({ apples })
})

on('GET', '/:id', async function ({ req, jsend }) {
  const id = req.param('id')
  const apple = Apple.findById(id)
  return jsend({ apple })
})

export default applesRouter

~/src/bananas/bananas.model.js

import { createSchema, createModel } from 'mongo-hono'

const schema = createSchema({
  name: {
    type: String,
    alias: 'alias',
    required: true,
    unique: true
  }
})

schema.set('timestamps', true)

const Banana = createModel({ name: 'Banana', schema })

export default Banana

~/src/bananas/bananas.router.js

import { createRouter, useRouter } from 'mongo-hono'
import Banana from './bananas.model.js'

// const bananasRouter = createRouter('/bananas')
// const { on } = bananasRouter
const [bananasRouter, on] = useRouter('/bananas')

on('GET', '/', async function ({ jsend }) {
  const bananas = await Banana.find()
  return jsend({ bananas })
})

on('GET', '/:id', async function ({ req, jsend }) {
  const id = req.param('id')
  const banana = await Banana.findById(id)
  return jsend({ banana })
})

on('POST', '/', async ({ jsend }) => {
  const banana = new Banana({ name: 'test banana' })
  await banana.prudentSave()
  return jsend({ banana })
})

export default bananasRouter

WebSocket Example

Folder

  • src
    • ws
      • ws.router.js
    • index.js
    • router.js
  • static
    • index.html

~/src/index.js

import { createApp } from 'mongo-hono'

// createApp(<appName>), the default appName is default.
const app = await createApp()
const { routers } = await import('./routers.js')

 app
  .useStatic('/static')
  .useRouters(routers)
  .listen(3000)

console.log('Server is running on http://localhost:3000')

~/src/router.js

import wsRouter from './ws/ws.router.js'

export const routers = [
  wsRouter
]

~/src/ws/ws.router.js

import { useRouter, useWebSocket } from 'mongo-hono'

const [wsRouter, on] = useRouter('/ws')

// useWebSocket(<appName>), the default appName is default.
const { create, deleteOne, broadcast, upgradeWebSocket, getLength } = useWebSocket()

on('GET', '/', upgradeWebSocket((context) => ({
  onOpen(event, ws) {
    console.log('Connected')
    create(ws)
    broadcast(getLength())
  },
  onMessage(event, ws) {
    console.log(`Message from client: ${event.data}`)
    ws.send('Hello from server!')
  },
  onClose(event, ws) {
    console.log('Connection closed')
    deleteOne(ws)
    broadcast(getLength())
  }
})))

export default wsRouter

~/static/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>
<body>
  <div id="message"></div>
  <script>
    const ws = new WebSocket('ws://localhost:3000/ws')

    ws.onopen = () => {
      console.log('open')
      // ws.send('Hello from client!')
    }

    ws.onmessage = (event) => {
      document.querySelector('#message').innerText = event.data
    }

    ws.onerror = () => {
      console.log('error')
    }

    ws.onclose = () => {
      console.log('close')
    }
  </script>
</body>
</html>

Q & A

How to set error messages?

You can use set methods or just change the file.

A simple example:

import { setUniqueErrorMessage } from 'mongo-hono'

setUniqueErrorMessage((prop, alias) => {
  return `${prop}: ${alias} has been used`
})

The default error messages:

const state = {
  setRequiredErrorMessage(prop, alias) {
    return `${prop} is required`
  },
  setMinlengthErrorMessage(prop, alias, minlength) {
    return `The minlength of ${prop} is ${minlength}`
  },
  setMaxlengthErrorMessage(prop, alias, maxlength) {
    return `The maxlength of ${prop} is ${maxlength}`
  },
  setMinErrorMessage(prop, alias, min) {
    return `The min of ${prop} is ${min}`
  },
  setMaxErrorMessage(prop, alias, max) {
    return `The max of ${prop} is ${max}`
  },
  setEnumErrorMessage(prop, alias) {
    return `Not a valid value for ${prop}`
  },
  setUniqueErrorMessage(prop, alias) {
    return `${prop} has been used`
  },
  setUserDefinedErrorMessage(prop, message) {
    return `${prop}: ${message}`
  }
}

NOTE: The default value of alias is an empty string.

How to throw an error to the error handler?

Example:

throw new Error('400 - message 1, message 2, message 3')

Return:

{
  "code": 400,
  "status": "client-error",
  "error": "BadRequest",
  "errorMessages": [
    "message 1",
    "message 2",
    "message 3"
  ]
}

What the jsend method does?

Example:

on('GET', '/', ({ jsend }) => {
  return jsend({ apples: [] })
})

Return:

{
  "status": "success",
  "data": {
    "apples": []
  }
}

Middleware

jwt

import { verify } from 'hono/jwt'

export function jwt({ secret, ignore, ignoreStartWith }) {
  return async function ({ req, set }, next) {
    if (ignore.has(req.path)) {
      return await next()
    }

    for (let i = 0; i < ignoreStartWith.length; i++) {
      if (req.path.startsWith(ignoreStartWith[i])) {
        return await next()
      }
    }

    const token = req.header('Authorization') || ''

    if (!token) {
      throw new Error('403')
    }

    try {
      const payload = await verify(token.split('Bearer ')[1], secret)
      set('jwtPayload', payload)
    } catch {
      throw new Error('403')
    }

    await next()
  }
}

userInfo

import User from './users/users.model.js'

export async function userInfo({ get }, next) {
  const jwtPayload = get('jwtPayload')
  if (!jwtPayload) {
    return await next()
  }
  const user = User.findById(jwtPayload.id)
  set('user', user)
  await next()
}
1.0.16

5 months ago

1.0.15

6 months ago

1.0.14

6 months ago

1.0.13

6 months ago

1.0.12

6 months ago

1.0.11

6 months ago

1.0.10

6 months ago

1.0.9

6 months ago

1.0.8

6 months ago

1.0.7

6 months ago

1.0.6

6 months ago

1.0.5

6 months ago

1.0.4

6 months ago

1.0.3

6 months ago

1.0.2

6 months ago

1.0.1

6 months ago

1.0.0

6 months ago