There are a lot of frameworks available in the JavaScript/typescript ecosystem.
PURISTA is more than a classical framework for building REST APIs.
It focuses on two big topics.
Building the logic behind the endpoints fast & efficiently in a product(ion) ready way.
Enable the project to not only scale from a technical perspective. The project will be enabled to scale as a project with more people, more features, and more requirements.
The idea
PURISTA adapts the idea of independent, small functions from serverless and FaaS.
These single functions are connected via a message-based approach, which also adapts event-driven patterns.
How messages are exchanged between separated functions and how single functions are grouped or deployed is a free choice.
It also does not matter for the implementation of the functions.
The benefits
Because of this simple idea, it becomes possible to:
- orchestrate and deploy the functions as one large monolith
- group them by domains and deploy them as microservices
- deploy them as single serverless functions (FaaS)
- mix up the orchestration and deployment
- free choice underlying infrastructure and vendor
- scale work across available "human pool"
- add features fast like spikes or PoCs
The example
A more detailed example and walkthrough can be found on the website PURISTA handbook. Here is a ruff overview how it works:
mkdir example
cd example
npx @purista/cli init
Create a service, which is a logical, versioned group of functions.
purista add service
Create your first command:
purista add command
This will output something like this
🎉 The command "sign up" in service "user" version1 is created 🎉
start adding your business logic here:
./src/service/user/v1/command/signUp/signUpCommandBuilder.ts
In the mentioned file /src/service/user/v1/command/signUp/signUpCommandBuilder.ts
you will add the business logic. In the same file, you can also add more information. Like how this command might be exposed.
In the same directory, you will find the prepared schema files, the unit test file, and a type file.
Here, you only need to align the schema according to the input and output for your function. Typescript types will be automatically generated.
Create your first subscription:
purista add subscription
This will basically generate a similar structure and similar files.
The difference between commands and subscriptions is, that commands are invoked by someone who is expecting a return value.
Subscriptions are a passive part, which is listening for messages (events). They can also emit their own events as results, which might be consumed by other subscriptions.
Adding functions is quite simple. But it is also simple to get them running.
As an example, you might want to deploy them as microservices. This would be some index.ts
file like this:
import { AmqpBridge } from '@purista/amqpbridge'
import {
getNewInstanceId,
gracefulShutdown,
initLogger,
} from '@purista/core'
import { getHttpServer } from '@purista/k8s-sdk'
import { theServiceV1Service } from './service/theService/v1/'
const main = async () => {
// create a logger
const logger = initLogger()
// set up the eventbridge and start the event bridge
const eventBridge = new AmqpBridge({
instanceId: process.env.HOSTNAME || getNewInstanceId(),
config: {
url: process.env.AMQP_URL,
},
})
await eventBridge.start()
// set up the service
const theService = theServiceV1Service.getInstance(eventBridge)
await theService.start()
// create http server
const server = getHttpServer({
logger,
// check event bridge health if /healthz endpoint is called
healthFn: () => eventBridge.isHealthy(),
// optional: expose the commands if they are defined to have url endpoint
services: theService,
// optional: expose service endpoints at [apiMountPath]/v[serviceVersion]/[path defined for command]
// defaults to /api
apiMountPath: '/api',
})
// register shut down methods
gracefulShutdown(logger, [
// start with the event bridge to no longer accept incoming messages
eventBridge,
// optional: shut down the service
theService,
// stop the http server
server,
])
// start the HTTP server
// defaults to port 8080
// optional: you can set the port in the optional parameter of this method
await server.start()
}
main()
You can imagine that it is also simply possible to spin up multiple different services in the file to deploy as a monolith.
By simply adding more services and functions, you can quickly build whole systems like those shown in this picture:
There are a lot more things PURISTA will provide. For example:
- config stores
- secret stores
- state stores
- webserver
- OpenTelemetry support built into the core of the framework
- support of different message brokers and vendors
...and much, much more available right now or in the upcoming weeks and months.
While the project is in some early stages and a lot of features will need to come, it is worth having a look at it.
Try it out!
Any feedback, ideas, hints, help, and so on are highly welcome.
You can also join the Discord Channel to get in touch with the maintainers and other developers!
Top comments (0)