Skip to content

Context

@justomx/context is a powerful library designed to manage and propagate contextual data within Jüsto projects. Contextual data, such as traceId, userId, and more, are commonly used to track the flow of requests through various microservices and processes. This library automates the management of such context, ensuring that key information is consistently available across requests, middleware, and services. It supports generating, mutating, and automatically filling in contextual fields, which is particularly useful in distributed systems and microservice architectures.

To install the library, simply run the following command in your terminal:

Install dependency @justomx/context
npm install --save @justomx/context

The Jüsto context (JustoContext) is an interface that holds key information for a request. It contains the following attributes:

interface JustoContext {
traceId?: string
country?: string
warehouse?: string
platform?: string
platformVersion?: string
clientAppName?: string
userId?: string
userAgent?: string
}
  • traceId: This attribute is auto-generated as a unique identifier for each request. If traceId is null, a UUID is assigned automatically.

The library includes several middlewares that help populate and manage the context within an Express.js application:

The RequestContextMiddleware sets the context for each incoming request by creating a JustoContext object. It extracts values from the request headers and populates the context with relevant information.

The RequestIdMutationMiddleware is responsible for mutating the request ID. It updates the request header X-Justo-RequestId to X-Justo-Trace-ID. This middleware is useful in scenarios where microservices may receive requests with different header naming conventions.

The UserIdAutofillMiddleware automatically fills the userId header in the request. It follows these steps:

  1. Checks if the JustoContextHeaderNames.userId header is already present in the request. If it is, the middleware proceeds to the next one.

  2. If the header is absent, it attempts to extract the userId from various sources:

    • a. From the ‘Authorization’ header, by extracting the userId from a JWT (JSON Web Token) using the function extractUserIdFromToken().
    • b. From the query parameters (query) if the userId is present as a string.
    • c. From the route parameters (params) if the userId is present as a string.
    • d. From the request body (body) if the userId is present as a string.
  3. If a userId is found, it is added to the request header using JustoContextHeaderNames.userId.toLowerCase().

  4. Finally, the middleware calls the next() function to continue to the next middleware in the chain.

This ensures that the userId is always available in the request header, which can be critical for subsequent middleware or service handlers.

The CountryAutofillMiddleware automatically fills the country header in the request if it is not already set. It checks if the header is present; if not, it tries to extract the country value from query parameters, route parameters, or the request body. If a country is found, it is added to the request headers, and the middleware proceeds.

Similar to the country middleware, WarehouseAutofillMiddleware ensures that the warehouse header is present in the request. If it’s not, it extracts the warehouse value from query parameters, route parameters, or the request body and adds it to the request headers.

To retrieve the current context in your application, you can use the AsyncJustoContextStorage class:

src/index.ts
const storage = AsyncJustoContextStorage.getInstance()
const ctx = storage.getContext()
console.log({ ctx })

This will give you access to the contextual data associated with the current request or process.

If you need to specifically access the traceId from the context:

src/index.ts
const storage = AsyncJustoContextStorage.getInstance()
const traceId = storage.getTraceId()
console.log({ traceId })

This will log the unique identifier for the request, which can be used for logging or tracking purposes.

Here’s an example of how to integrate @justomx/context middlewares with an Express.js application:

src/infrastructure/http/server.ts
const app = express()
app.use(express.json({ limit: '15mb' }))
app.use(express.urlencoded({ extended: true }))
// Optional middlewares
app.use(RequestIdMutationMiddleware.mutate())
app.use(UserIdAutofillMiddleware.build())
app.use(CountryAutofillMiddleware.build())
app.use(WarehouseAutofillMiddleware.build())
// Set request context middleware (required)
app.use(RequestContextMiddleware.setContext())
app.get('/', (_req, res) => {
res.status(200).json({ hello: 'world!' })
log('Handling GET / request')
})

This setup ensures that every incoming request will have a consistent context, and optional middlewares can be added to enrich the request with user ID, country, and warehouse information.

You can also use AsyncJustoContextStorage in non-HTTP environments, such as cron jobs or background tasks:

src/index.ts
const cron = new CronJob('*/1 * * * * *', () => {
AsyncJustoContextStorage.getInstance().run({}, () => {
log('[Start]: CronJob!')
const service = new GreetingService()
service.sayHello()
log('[End]: CronJob!')
})
})
cron.start()

This ensures that even in background tasks, the context is properly set and can be accessed or logged as needed.


With this extended documentation, the functionality and usage of the @justomx/context library should be clearer and easier to understand for developers working on Jüsto projects. The additional detail should help convey the importance and flexibility of the context management system.