Skip to content

Repository files navigation

@data-fair/lib

A collection of javascript functions, components, types, etc to help work inside the data-fair stack.

All dependencies are declared as optional peer dependencies, you should install them yourself as required by your usage.

npm i @data-fair/lib

Types

Some shared contracts, typescript types, etc.

SessionState

Describes the current session, the logged in user, their organizations, etc. Usually used on the client side through useSession and on the server side through the session middleware.

import{typeSessionState}from'@data-fair/lib/types/session-state'

build.ts

This module implements a strategy similar to Fastify for validation and serialization. But it is a simple optional tool used to improve our apis, not a framework.

  • validation of body and query is encouraged (headers are not usually included because they are much less frequently manipulated on a per-route basis)
  • type casting : the schemas act as type guards
  • fast response serialization using fast-json-stringify
  • use json-schema-to-typescript to create coherent schemas and types
  • a provided script helps building a typescript module with types, compiled validation function and compiled serialization function

Create a directory structure compatible with the build script:

types/
├── my-type
│ └── schema.json

Schemas can contain instructions to generate optional functionalities:

"x-exports": ["types", "validate", "stringify", "schema"],

In the types directory install build peer dependencies:

npm i -D ajv ajv-formats ajv-errors fast-json-stringify json-schema-to-typescript @bcherny/json-schema-ref-parser

In the types directory's package.json create this script:

"scripts": {
"build": "node node_modules/@data-fair/lib/types/build.js ./ && tsc"
},

Running this script should fill the types directory like so:

types/
├── my-type
│ ├── index.d.ts
│ ├── index.js
│ ├── index.ts
│ ├── schema.json
│ └── validate.js

In the nodejs service, install peer dependencies:

npm i ajv-i18n flatstr

Then in a route use the built modules:

import*asmyBodySchemafrom'types/my-body'import*asmyQuerySchemafrom'types/my-query'import*asmyResponseSchemafrom'types/my-response'router.post('',asyncHandler(async(req,res)=>{// after these lines body and query will be typed and the schema will be validated// a 400 error is thrown in case of failureconstbody=myQuerySchema.validate(req.body,req.session.lang,'body')constquery=myQuerySchema.validate(req.query,req.session.lang,'query')constresult=await ...
res.type('json').send(myResponseSchema.stringify(result))}))

Vue

useSession

This composable for Vue 3 provides a reactive session state and useful methods (login, logout, etc).

Install peer dependencies:

npm i @vueuse/integrations ofetch jwt-decode debug universal-cookie

Use as a nuxt plugin in js (plugins/session.js):

import{useSession}from'@data-fair/lib/vue/use-session'exportdefaultdefineNuxtPlugin(async(nuxtApp)=>{constsession=awaituseSession({req: nuxtApp.ssrContext?.event.node.req})return{provide: { session }}})

Use as a nuxt plugin in typescript (plugins/session.ts):

import{useSession,typeSession}from'@data-fair/lib/vue/use-session'declare module '#app'{interfaceNuxtApp{$session: Session}}declare module 'vue'{interfaceComponentCustomProperties{$session: Session}}exportdefaultdefineNuxtPlugin(async(nuxtApp)=>{constsession=awaituseSession({req: nuxtApp.ssrContext?.event.node.req})return{provide: { session }}})

Express

session

This middleware provides a thin layer for connecting to simple-directory using jwks, validating session tokens and casting to the SessionState type (see section payload). This module extends the standard express Request type to add the session property, this way all access to req.session is fully typed and safe.

Install peer dependencies:

npm i jsonwebtoken jwks-rsa cookie
import{asyncHandler,initSession}from'@data-fair/lib/express/index.js'exportconstapp=express()constsession=initSession({directoryUrl: config.directoryUrl})app.use(session.auth)router.get('',asyncHandler(async(req,res)=>{if(!req.session.account){res.status(401).send();return}
...
}))

Nodejs

Prometheus

Every Web service and all other processes (workers, etc) should expose prometheus metrics for monitoring.

Install peer dependencies:

npm i prom-client

Run a mini webserver to serve metrics:

import*asprometheusfrom'@data-fair/lib/node/prometheus'
...
awaitprometheus.start(config.prometheus.port)...awaitprometheus.stop()

Increment the shared "df_internal_error" metric and produce a corresponding log:

import*asprometheusfrom'@data-fair/lib/node/prometheus'app.use(function(err: HttpError,_req: Request,res: Response,next: NextFunction){
...
if(status>=500){prometheus.internalError('http','failure while serving http request',err)// TODO: prometheus}
...
})

Define a custom metric and use it:

constmyCounter=newCounter({name: 'df_my_counter',help: '...',labelNames: ['myLabel']})...myCounter.inc({myLabel: 'label value'})

Define a custom global metric (a global metric value depends on a shared state instead of only the activity of the current process):

import*asprometheusfrom'@data-fair/lib/node/prometheus'newclient.Gauge({name: 'df_my_gauge',help: '...',registers: [prometheus.globalRegistry],asynccollect(){this.set(awaitdb.collection('collection').estimatedDocumentCount())}})

About

A collection of javascript functions, components, types, etc to help work inside the data-fair stack.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages