I'm new to nestjs, I'm studying nestjs from its documentation.
I see the word context a lot in the documentation.
For example:
Execution Context
Application Context
Http Context
I want to know what "Context" means.
Any help would be appreciated.
As per the official documentation regarding Execution context:
Nest provides several utility classes that help make it easy to write applications that function across multiple application contexts (e.g., Nest HTTP server-based, microservices and WebSockets application contexts). These utilities provide information about the current execution context which can be used to build generic guards, filters, and interceptors that can work across a broad set of controllers, methods, and execution contexts.
If I translate properly, in NestJS, the context corresponds to the way you mount your NestJS application; like HTTP, RPC for microservices, WebSocket, but could also be just a standalone app (i.e. without any network listeners).
Related
So we have decided to use NestJS to build our web-app with, and we have this ongoing argument about whether we should use a Microservice or a Standalone app to implement our queue-interactions module with.
A bit of background - we use Amazon SQS as our queue provider, and we use the
bbc/sqs-consumer package for handling the connection.
Now one approach is to use a microservice, in a similar fashion to what is done here: https://github.com/algoan/nestjs-components/tree/master/packages/google-pubsub-microservice
I believe the implications are pretty clear, and it seems as if the NestJS documentation really pushes you towards microservices here, if only because all the biult-in implementations are for queues/pubSub services (rabbitMQ, kafka, redis...).
On the other hand, you can choose to use a standalone app, which I feel is basically a microservice but without controllers.
Since we opted for using a 3rd party package to handle the actual transport and all the technical details, this feels in a way more appropriate. We don't actually need to send the messages from the messageHandler to some controller and then process it, if we can process it directly from the messageHandler, no controllers included.
Personally, it seems to me that if we don't want to go into details with the transport implementation (i.e. use sqs-consumer package for it) then the microservice approach, while works perfectly, is an overkill. A standalone app feels like it would give us the benefits of separating the "main" and the "queues" processes, while maintaining simplicity of implementation as much as possible.
Conversely, using a Microservice feels more natural to others. The way to think about it is that it doesn't matter whether we choose to implement transport ourselves or use some package, the semantic meaning is the same in the way that we have some messages coming into our app from outside, thus using a custom transport Microservice really is the most appropriate solution.
What do you guys think about it?
Would you use the Microservice or the standalone approach?
And in general, when would you choose Microservice over a Standalone app and vice-versa?
Let's assume the following situation:
We have several webservices based on Nest.js technology
The services perform CRUD operations in the area of their domain
The services do not have business logic (they can add, change, delete, return data, they know the relationships between entities, but also between domains (e.g. through Apollo Federation)
Everything works fine so far.
However, we face the problem of business processes, validation, business rules and everything that goes with it. So we have to code this logic somehow or use some engine (eg Camunda).
As far as I understand that Camunda can send requests from Service A to Service B in the BPMN process e.g. via HTTP.
But what if several activities are performed in the same service?
Isn't it better to make requests to the same service at the service level layer? Is it possible in Cmunda?
E.g.
WebService1 has a POST Customer/ endpoint which calls CustomerService.AddCustomer (data) and CustomerRoles.AddRole (data). Can we call CustomerRoles.AddRole in Camunda?
My question is mainly about node.js / nestjs.
Forgive me, but I don't think I can describe it more clearly :(
In general you can use Camunda not only at the highest orchestration layer, for the end-to-end business process, but also inside the micro service. Benefits include state management, error handling, retries, exception handling, possible compensation. (What happens if AddCustomer succeeds, but AddRole fails?).
There are orchestration vs choreography considerations. Latency requiremnts may also be relevant. I recommend these two reads, which illustrate the benefits/trade-offs and design decision well:
https://blog.bernd-ruecker.com/the-microservice-workflow-automation-cheat-sheet-fc0a80dc25aa
and
https://blog.bernd-ruecker.com/3-common-pitfalls-in-microservice-integration-and-how-to-avoid-them-3f27a442cd07
Why don't you implement a little proof of concept and see what it could look like? If NextJS is your world, you may like to start with a Camunda 8 SaaS trila and https://github.com/camunda-community-hub/nestjs-zeebe#readme
To speed up development for my next Node-API I was looking for a suitable Framework. In the past I was building my APIs with express only.
One Design pattern I always found useful is to completely seperate the business logic from route-handling in services. Those services only accept the required information (like a user id or data) and return a promise resolving the result of the operation.
This way it is easy to reuse these services in other routes, to combine them, test them, or call them based on schedules or other events - totally independent from endpoint-calls. Routing and Middleware take care of access-controll, error-handling and respondig.
Looking at the documentations of those frameworks (sailsjs, keystonejs, ...) I mostly see the business-logic tightly coupled to individual routes, directly accepting request objects and handling the responses. Only as an afterthought it seems there is sometimes offered a way to extract "often used code" into helper functions.
Am I missing something? How come this pattern seems to be the standard of API design? Is this a best practice for a reason?
It might have to do with Node.js services being smaller in size. If you're coming from an enterprise background, you're well aware mixing business-logic with controller code doesn't fly in the long run. Perhaps small projects can get away with defying that, but once the size increases, you can't avoid the laws of physics. It's best to separate concerns and keep the codebase maintainable.
I'd also add that below services, it's good to have a separate layer that handles talking to outside process boundaries. That way, you can test business logic in isolation by providing appropriate test doubles for integrations. Here's a longer explanation of how it would work in a Node project: Organize Node.js API project using 3-layer architecture.
I know that Corda is in the process of removing its web server module and in the documentation they suggest the use of other frameworks.
In one example ("spring-observable-stream") they use Spring Boot for the server-side APIs and use an RPC call to the actual running Corda node. That's fine and comparable with what I have to do.
In that example, the author import the specific Corda's RPC code, along with the code of the actual flow (and states) needed.
What I want to ask here is if it's possible to avoid that tangle and keep the web server APIs independent from the actual Corda/CordApp's code by using a general RPC library (any advice ?).
If, instead, I must import the Corda-specific code (there is a reason ?), I'd like to ask you:
What is the minimum necessary to do so from a Gradle perspective ?
Is it possible to implement some sort of plugin on the CordApp to reduce that tangle ?
To be honest, I'm interested in a more general way for interacting with the CordApp (e.g. from Python), but I know that due to the AMQP integration not yet ready, we have to stay on the JVM for now. So, feel free to answer just about what we need to do as of today from Kotlin (which I have to use for a short-term PoC)…
Thank you in advance!
Currently, your server has to depend on the Corda RPC library to interact with nodes via RPC. Corda doesn't yet expose an independent format for sending and receiving messages via RPC.
Your server also needs to depend on any CorDapps that contain flows that the server will start via RPC, or that contain types that will be returned via RPC. Otherwise, your server will not be able to start the flows or deserialise the returned types.
If you're using Gradle, here's what a minimal dependencies block might look like:
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
cordaCompile "net.corda:corda-rpc:$corda_release_version"
compile "com.github.corda:cordapp-example:release-V1-SNAPSHOT"
}
Here, we're depending on the corda-rpc library, and also using JitPack to depend on the CorDapp where we define the flows and states that we want to start/return via RPC.
If you want, you can modularise the CorDapp so that all the classes you need to depend on for RPC are included in a separate module, and only depend on that module.
I'm learning more about ArangoDB and it's Foxx framework. But it's not clear to me what I gain by using that framework over building my own stand alone nodejs app for API/access control, logic, etc.
What does Foxx offer that a regular nodejs app wouldn't?
Full disclosure: I'm an ArangoDB core maintainer and part of the Foxx team.
I would recommend taking a look at the webinar I gave last year for a detailed overview of the differences between Foxx and Node and the advantages of using Foxx when you are using ArangoDB. I'll try to give a quick summary here.
If you apply ideas like the Single Responsibility Principle to your architecture, your server-side code has two responsibilities:
Backend: persist and query data using the backend data storage (i.e. ArangoDB or other databases).
Frontend: transform the query results into a format acceptable for the client (e.g. HTML, JSON, XML, CSV, etc).
In most conventional applications, these two responsibilities are fulfilled by the same monolithic application code base running in the same process.
However the task of interacting with the data storage usually requires writing a lot of code that is specific to the database technology. You need to write queries (e.g. using SQL, AQL, ReQL or any other technology-specific language) or use database-specific drivers.
Additionally in many non-trivial applications you need to interact with things like stored procedures which are also part of the "backend code" but live in the database. So in addition to having the application server do two different tasks (storage and rendering), half the code for one of the tasks ends up living somewhere else, often using an entirely different language.
Foxx lets you solve this problem by allowing you to move the logic we identified as the "backend" of your server-side code into ArangoDB. Not only can you hide all the nitty gritty of query languages, edges and collections behind a more application-specific API, you also eliminate the network overhead often necessary to handle requests that would cause more than a single roundtrip to the database.
For trivial applications this may mean that you can eliminate the Node server completely and access your Foxx API directly from the client. For more complicated scenarios you may want to use Node to build external micro services your Foxx service can tap into (e.g. to interface with external non-HTTP APIs). Or you just put your conventional Node app in front of ArangoDB and use Foxx to create an HTTP API that better represents your application's problem domain than the database's raw HTTP API.
It's also worth keeping in mind that structurally Foxx services aren't entirely dissimilar from Node applications. You can use NPM dependencies and split your code up into modules and it can all live in version control and be deployed from zip bundles. If you're not convinced I'd suggest giving it a try by implementing a few of your most frequent queries as Foxx endpoints and then deciding whether you want to move more of your logic over or not.