Table of contents
We're excited to announce the release of Godspeed version 2 (Github). In our knowledge, it is the world's first 4th generation microservices "meta" framework. The first attempt at abstracting, standardising and democratising development of modern API and event driven services, independent of the framework, language, integrations and protocols used. Currently we are shipping the port for Nodejs and Bunjs. Java is under construction and expected to come out later this year.
And a promise: In alignment with our commitment to a fair way of doing things - "FOSS: From Free to Fair" all our dev tools will forever be free to run in self hosted fashion for not-for-profits, individuals, IT services teams, freelancers and businesses who are yet to make profit or raise series A funding.We invite developers to help us build this unique project together to bring a paradigm shift in in the way teams build and maintain great products across diverse stacks.
The Nodejs module's shipping comes as a paradigm shift from the V1, with a new feather light packaging, decoupled architecture, and multitude of new features and enhancements to take your development experience to new heights. Before we dive into the highlights, let’s see the major differences or enhancements between V2 and V1.
Differences from V1
1) Packaging: V2 ships as a node.js module with a command line utility. This makes it super lightweight and easy to adapt into new or even existing Node.js or Bun.js projects. The packaging of V1 was via Remote Containers based approach, which proved to be a bulky process to setup, build and run on a developer machine. Despite the theoretical promise of better practices that it holds, we realized that remote containers come at their own cost. Even though we have had initial first wins across our enterprise customers, we realised that we needed to shift to a feather light and quick to get started approach.
npm install -g @godspeedsystems/godspeed
2) Modularity: The framework now ships with eventsource and datasource as modular plugins, which can be installed via command line or handcrafted by developers within their project src folders. They can also take help of Godspeed's GPT (Available for private preview). But creating plugins is straightforward and free. Anyone can do it!
The plugins and the functions (js, ts, yaml) have dynamic imports in the rest of the code, so that the eventsource and datasource sdks are not coupled with the business logic. They should be able to replace an integration like prisma by just overwriting a single file in their plugin, instead of changing their entire microservice! Check out this video on decoupled architecture
godspeed plugin add
Creating your own plugins
You can create your own plugins as documented here. Feel free to browse the implementations our plugins to understand how they are setup.
3) Native language functions: In V1, developer could write workflows in YAML only. While it has a shorthand syntax for simpler things like datasource calls and combining or transforming data, it is not suited for complex business logic like nested loops. Hence developer's freedom to choose how to write business logic was given high importance in this release. V2 allows developers to write JS and TS functions and plugins to be used within inline scripts in YAML. This gives them full freedom and control over their app. Node.js or Bun.js app, but they can now leverage Godspeed’s opinionated ways of how to develop services in a better way with guardrails. Like YAML workflows, native workflows can be directly set as a event handler or called from other functions aka workflows .
import { GSContext, GSStatus, GSCloudEvent } from "@godspeedsystems/core";
/**
* Here we call a datasource and can apply any busienss logic
*/
export default async function (ctx: GSContext, args: any) {
//Ctx object has the basics you need to write any business logic in TS/JS
const {
logger: pinoLogger,
childLogger: pinoChildLogger,
inputs, outputs, functions, datasources,
config, mappings, plugins: scriptFunctions, forAuth, exitWithStatus
} = ctx;
//Accessing deserialized inputs from the event source
const {user, body, params, query, headers} = inputs.data;
//Apply some business logic. Call another function or workflow etc.
//Note: this is not stopping you from statically importing the same function modules
const sum = await functions['com.biz.sum'](args.x,args.y);
// Invoking any datasource method
// The args can be completely custom as per the plugin implementation
const mongooseCallArgs = {"name":"mastersilv3r"};
// There is a `meta` key in args which acn be used to send meta information to the plugin's execute() calls
// The plugin knows how to handle thse calls
// In `meta` you can set your custom parameters on top of the arguments for the execute() method of the plugin
// Prepare the args: Add entityType, method name and authorization access rules to the datasource call
const metaArgs = {
entityType: 'Templates',
method: 'findOne',
authzPerms: { //If supported by the datasource plugin
CollectionName: { //Collection Name
can_access: ['name', 'email'], //Fields allowed to retrieve for this user
where: { //Which rows are allowed to be returned to this user
tenant_id: user.tenantId,
owner_id: user.ownerId
}
}
}
};
const res = await ctx.datasources.mongoose.execute(ctx, {
...mongooseCallArgs,
meta: metaArgs
});
if (!res.success) {
return new GSStatus(false, res.code || 500, undefined, {message: "Internal Server Error", info: res.message})
}
return new GSStatus(true, 200, undefined, res || {",ess": 5});
}
4) Doubling down on Schema driven development: While we already supported schema driven development in V1, we have now added Apollo Graphql and multiple http services (like Express and Fastify) all getting created and working with incoming and outgoing data deserialization, serialization, validations, authentication, authorization via the Godspeed + Swagger hybrid event schema. This way developers work on one standard schema format, and can expose their APIs via different protocols without writing or changing a single line of code in their business logic or schema validations! Check out this video on Schema Driven Development
Lets check difference (or similarity) between sample HTTP/REST and Graphql event schemas
http event
http.get./sample_api:
summary: sample
description: sample http event example
fn: http_sample
body:
content:
application/json:
schema:
type: object
properties:
name:
type: string
responses:
200:
content:
application/json:
schema:
type: object
Graphql event
Apollo.post./sample:
summary: sample
description: sample graphql event example
fn: graphql_sample
body:
content:
application/json:
schema:
type: object
properties:
name:
type: string
responses:
200:
content:
application/json:
schema:
type: object
They are the same! See how you can add Apollo Graphql to your service or generate CRUD API in REST.
Now, having seen the major highlights, lets dive deep into individual updates.
New Features
1) Introducing Event source: Event source is introduced to capture and define entry points in the Godspeed Framework, all following a standard schema syntax, irrespective of the protocol, whether async or sync. Do check the http, kafka, graphql etc event sources in Godspeed's plugin directory.
2) Datasource Enhancements: Datasource serves as central origins for data querying and storage from APIs or datasources. Let's see examples from the AWS plugin
Aws plugin scaffolding
├── src
├── datasources
│ ├── types
│ | └── aws.ts
| |
│ └── aws.yaml
│
├── events
|
├── eventsources
│
└── functions
|
└── aws_list.yaml
AWS configuration file
type: aws
default_client_config: # uses env var declared in config/custom-environment-variables.yaml
region: <%config.region%>
credentials:
accessKeyId: <%config.accessKeyId%>
secretAccessKey: <%config.secretAccessKey%>
# service type is the name of the npm module for ex. @aws-sqk/client-dynamodb or @aws-sqk/client-s3 etc
# The `types` key can have service type to sdk's client names mappings when coding
types:
dynamodb: DynamoDB
s3: S3
lambda: Lambda
ssm: SSM
sqs: SQS
services:
s3:
type: s3
config: #overriden config for s3
region: <%config.s3Region%>
credentials:
accessKeyId: <%config.s3AccessKeyId%>
secretAccessKey: <%config.s3SecretAccessKey%>
s3_1: #another S3 service instance
type: s3
dynamodb:
type: dynamodb
sqs:
type: sqs
ssm:
type: ssm
lamdba:
type: lambda
Sample AWS function call
id: aws_workflow
tasks:
- id: aws_list
fn: datasource.aws.s3.listObjects
args: <% inputs.body %>
3) Authorization:
Implementation of authorization in Godspeed V2. Adopt any RBAC and ABAC policies with rule engines and distributed systems, using any databases or policy engines. We have provided a way-agnostic method to have custom authz at event and workflow/task levels, including very fine grained database access limiting access to not just tables but rows and columns! You can customise the implementation to your org's use case.
Event level authz
"http.get./helloworld": authn: true fn: helloworld authz: - fn: com.gs.transform id: try_auth_2_authz args: | <js% if (inputs.user.role === 'admin') { return { success: true, message: "Authorization passed", } } else { return { success: false, message: "Authorization failed" } } %>
Task level authz
id: task_authz tasks: - fn: com.gs.transform id: try_auth_3 args: success: true, data: { "tableABC": { "where": {ownerId: <%user.user_id%>, departmentId: <%user.department_id%>}, "can_access": ["column1","column2"] , "no_access": ["column1"] } }
4)DirectJS/TS Workflow Invocation
Allow native language Workflows to be directly called from events.
Example event
http.post./helloworld: fn: test body: content: application/json: schema: type: object responses: 200: content: application/json: schema: type: number
test.js
const {GSStatus} = require('@godspeedsystems/core'); module.exports = async(ctx)=>{ const x = parseInt(ctx.inputs.data.body.x) const y = parseInt(ctx.inputs.data.body.y) const responseData = x+y return new GSStatus(true, 200, undefined, responseData, undefined); };
5) Pluggable Observability in Godspeed v2:
Pluggable OTEL standard based monitoring of your services for capturing logs, traces, and metrics via simple configurations.
-
6) Godspeed GS-Kit:
AI-Powered React Front-End Starter Kit for Rapid Development from OpenAPI/Swagger Specifications. This is a small useful utility when it comes to initializing a React project with API/data/store connectivity generated from the Swagger spec of your backend service, along with Tailwind setup. A great place to get started with UI around your API!
-
7) Automated Swagger Generation:
Automated Swagger Generation for Smooth API Exploration.
8) Godspeed Plugin - graphql-as-eventsource:
Run a Graphql service on top of your database model in 5 minutes. Use the standard event schema syntax of Godspeed but instead of
http
saygraphql or Apollo or a keyword of your choice.
Sample graphql event(create_category.yaml)
Apollo.post./mongo/category: summary: Create a new Category description: Create Category from the database fn: create body: content: application/json: schema: type: object properties: name: type: string responses: content: application/json: schema: type: object
-
9) Godspeed Language Tools:
Enhanced Development Experience with VSCode Extension and Language Server. Autocompletion and validation of events, workflows and tasks happens through this VS plugin.
-
10) Godspeed Plugin - AWS as Datasource:
Introducing a Godspeed plugin for AWS as a datasource, exposing all the services of AWS via simple configuration files
11) Added Plugin Feature for Inlinescript
You can write funtions and use them within inline scripts of your YAML DSL within YAML workflows, eventsource and datasource configurations. Plugins are utility JS/TS synchronous functions designed to enhance inline scripting capabilities. You can write any piece of code in a plugin and access it inside your inline scripts at any time. Please note, this is not to be confused with Datasource or Eventsource plugins.
plugins/epoch/convertEpoch.ts
import format from 'date-fns/format';
export default function convertEpoch(inputTimestamp: string){
const newDateTime = new Date(inputTimestamp);
return format(newDateTime, 'yyyy-MM-dd HH:mm:ss');
}
- id: httpbinCof_step1
description: Hit http bin with some dummy data. It will send back same as response
fn: datasource.api.post./anything
args:
data:
default_date: <% epoch_convertEpoch(inputs.body.datetimestamp) %>
Improvements
1)Simplifying Return Values in TS/JS Functions and Event Handlers:
Improved handling of return values in TS/JS functions and event handlers.
Bug fixes
1) Failure to Read Some Environment Variables from .env File:
Fixed the issue with reading environment variables from .env files.
2)Fixed Return Bugs in V2:
Addressed return bugs for smoother execution.
3) Request Body Schema Reference Issue:
Fixed the issue where the request body schema, $ref, couldn't take reference from the definitions.
4) Fix Inline JS Script in EventSources YAML:
Resolved the issue with inline JS script not working during loading of EventSources YAML.
5) Response Schema Validation Issue:
Fixed the issue where response schema validation was not working.
6) Inline Scripts Not Supported by EventSource YAML:
Resolved the issue where inline scripts were not supported by EventSource YAML (http.yaml).
7) Config Module Environment Variable Issue:
Fixed the issue where the config module was unable to read environment variables from the .env file.
Do watch these videos on Security and Configure Over Code. Here is a getting started video & getting started Documentation link. Feel free to join our discord for any discussions.
What do you think about our philosophy of Godspeed’s meta design.
Ensure to check the provided links for detailed information on each feature, improvement, and bug fix.
Thank you for being a part of the Godspeed community! Your contributions and feedback drive us to new heights.
Happy coding! 🚀