Diving Deeper
In the previous section we got an understanding on how to setup a meta-framework based project for your local development and create a new project via cli commands. This section is dedicated to providing hands-on practice in constructing comprehensive backend services utilizing the meta framework and its associated plugins. Additionally, it aims to facilitate a thorough understanding of all the fundamental concepts underpinning the Godspeed framework.
Video Playlist for Detailed Walkthrough
Don't miss! Video Playlist of detailed guide to eventsources, events, functions and datasources: Watch here
As we move forward
Do ckeck the tenets, design principles and guardrails baked into the meta-framework as part of its design - helping teams develop microservices based applications with best practices.
The three pillars
Have you seen the three pillars of abstraction in the Meta-Framework?
You may want to check why you should use the 4th generation Meta-Framework versus creating apps using pure 3rd generation frameworks like Nodejs or Django stack from scratch.
Note: The Meta-Framework currently supports Nodejs based ecosystem
Moving forward
As mentioned in the getting started section all APIs and async events are together referred to as events
. And hence any source like Express, Fastify, Kafka, Apollo Graphql are called EventSources.
In getting started section we created a project that includes a simple 'hello world' example which uses an http Express eventsource, events and event handler functions.
Now we can move into further details.
In order to see detailed examples and documentation of eventsources, events and event handlers please visit Express HTTP Eventsource Plugin documentation.
Event Configuration
All event definitions are stored in
src/events
folders in YAML files. Each YAML file can have multiple events or a single event defined. The folder structure withinsrc/events
determines the categories (grouping of your API) that you will see in the generated Swagger and Postman collection. You can group events in any files and nested folders as per your need.
Now lets understand how our helloworld
api endpoint is working behind the scene
Open ./src/events/helloworld.yaml
"http.get./helloworld":
fn: helloworld # event handler function - the logic resides here
authn: false
params: #same as Swagger params.
- name: name
in: query
schema:
type: string
Lets understand the first line from the above snippet http.get./helloworld
.
http
: Protocol http eventsource
get
: method
/helloworld
: endpoint
We are exposing an endpoint with a get
method on http
protocol. This endpoint is calling a function fn
: helloworld
in the second line of the above code snippet.
For the sake of brevity, in the above example we have omitted further details of event configuration like the JSON schema of
body, query, headers, responses
and as wellauthn, authz
settings among more.
You can find in-depth introduction to event schema here.
The meta-framework follows Schema Driven Development and Single Source of Truth as its first guardrail. Check the blog here on reasons why this is an essential practice for any 10x engineering team. It allows you to use the Swagger (aka OAS3) spec which includes JSON schema spec, to define your event schemas as single source of truth. The schema format remains same independently of the eventsource which listens on an event.
From your event schemas the meta-framework generates the Swagger specs, Graphql schema (if applicable) and also enable input validation, output validation, authentication, authorization without explicitly writing boilerplate code.
The event configuration uses Swagger and JSON Schema for defining shape of requestBody, params, query, headers & responses
. The overall event schema has more configurations as well, like authn, authz
. Further the event schemas in the meta-framework are universally same across all event sources with only two variations per eventsource which are
- First line of the event URI may change based on the type of eventsource.
http.{method}.{url}: # http event URI - same for Express, Fastify and Graphql plugins
kafka.{topic}.{group_id}: # kafka event URI
cron.* * * * *.Asia/Kolkata: # cron event - Async events don't return response and hence don't need
responses
in the shema. But REST and Graphql events should have aresponses
section, defined in Swagger format.
For http service like Express, Fastify and Graphql, all events are defined in the same format. This way you learn once and reuse everywhere, independent of the event source which is capturing the event. This is the fourth guardrail of the Meta Framework - Decoupled or Modular Architecture.
Event Handler Functions
Event handlers are pure functions which take input as JSON and return output as JSON, independent of the eventsource from which the event originated. This is again another adoption of decoupled architecture approach in the meta framework.
Sample typescript event handler function Here is how a function handler looks like.
import { GSContext, PlainObject } from "@godspeedsystems/core";
export default function (ctx: GSContext) {
const {body, headers, params, query, user} = ctx.inputs.data;
const name: string = query.name; //name expected in request query
return {
data: 'Its working! ' + name, //the data key gets set as the body in API response
code: 200, //Response status code
success: true, //success can be true or false
headers: { //custom headers to be attached from this function call
custom_response_header: 'something'
}
}
//Note: if you wish to use static typing in returning the response instead of using JSON, you can return GSStatus. More on that below.
}
We are importing GSContext & GSStatus from core package of meta-framework. Go to their respective section to more about them.
Sample YAML function
The meta-framework gives you the option to write your logic in its custom YAML DSL as well. This DSL helps you reduce your lines of code and avoid boilerplate and is an alternative to writing logic in Typescript or Javascript functions. Its downside is that YAML does not have type checking and currently Godspeed does not support autocompletion of YAML workflows like you can have in Typescript within VSCode or another IDE.
id: helloworld
tasks:
- id: first_task
fn: com.gs.return
args:
data: <%'Its working! ' + inputs.body.name%>
code: 200
success: true #by default success is assumed to be true
headers:
custom_response_header: 'something'
The helloworld event is calling the above function written in YAML, which is executing a task with id first_task
. This task is calling fn: com.gs.return
function that takes argument name in an inline script.
So far we have seen how can we use Express plugin and also we created an endpoint which returns a response with some code and headers.
Swagger generation
The meta-framework gives you an autogenerated Swagger collection and UI to test your API endpoints.
If you are new to Swagger or in other words Open API Spec 3, along with JSON Schema standard, then we strongly suggest to study that. These are standards for defining schema of HTTP APIs. A Swagger schema can also be imported in a Postman collection, or generated from Postman.
Your Swagger docs are automatically generated and stored in /docs
folder when the project starts or you make a change to your eventsource or event schemas. The documentation is generated from a combination of settings at Eventsource and events levels.
- Eventsource level (refer the
docs
section in http.yaml). This is applicable for Express and Fastify eventsources. - Event level
- When you enable authentication on an event, its security scheme is set accordingly in generated swagger. By default authentication is enabled on all events when enabled on eventsource instance level itself.
requestBody
,params
,responses
,operationId
,id
,summary
,description
,tags
are also picked up or auto-calculated from event spec.
See more details on Swagger related configurations in http eventsource and event level both, in Express Plugin documentation
CRUD API generation
Checkout how to generate CRUD APIs in a step by step guide.
Graphql setup with schema generation
Check out the Apollo Graphql plugin documentation for more details.
Datasources
Datasources are any locations which allow to send or retrieve data. These could be another API service, message bus, file system, database, text search engine etc.
Using Datasource and Eventsource Plugins
You can import any datasource or eventsource in your project without writing code, with the available plugins for eventsources and datasources.
Eventsource Plugins
Currently officially supported eventsources plugins are Express Server, Fastify Server, cron, Kafka & Apollo Graphql Server
Datasource Plugins
Currently officially supported datasource plugins are Prisma, Mongoose, Axios, Memcached, Kafka, Redis, AWS
Creating Own Plugins
You can modify our existing plugins or create new plugins from scratch and reuse across your projects. A detailed overview of how to create eventsource plugins and datasource plugins exists.
JWT authentication
The Meta Framework currently supports standardised JWT authentication implementation across Express, Fastify and Apollo Graphql plugins.
Configure the eventsource to enable jwt authentication. More detailed information about authentication available here
Configuring JWT in Express "./src/eventsources/http.yaml"
Express, Fastify and Graphql plugins support standard way of handling JWT based authenticatin.
type: express
jwt:
issuer: <#config.issues#> # must be equal to the key iss in your jwt token
audience: <#config.audience#> #must be equal to the key aud in your jwt token
secretOrKey: <#config.secret#>This enables JWT authentication on all your endpoints for the given eventsource.
Disabling authentication on a given endpoint
You can disable authn on any endpoint by setting authn: false
"http.get./helloworld":
fn: helloworld
authn: false
Authorization (RBAC, ABAC, PBAC)
The meta-framework gives you full freedom to handle authorization (more details here) based on RBAC, ABAC or PBAC, in a generic way, independent of the event source. You can integrate any IAM or policy engine to use with the meta-framework.
Autorization at eventsource level Authorization can be a list of YAML instructions or just one function which could be in turn TS, JS or YAML function in Godspeed's DSL.
authz:
- fn: com.gs.is_allowed
# OR
authz: com.gs.is_allowed
Disabling authorization at event level
If authorization is enabled at eventsource level for all its events, but you wish to disable authorization for any particular events, you can disable authorization at an event level by saying authz: false
.
"http.get./helloworld":
fn: helloworld
authz: false
Customizing authorization at event level If authorization is enabled at eventsource level for all its events, but you wish to customise authorization for any particular events, you can disable authorization at the event level, by setting an authorization function or inline yaml workflow there itself.
"http.get./helloworld":
fn: helloworld
authz: com.biz.user_is_allowed_for_this_event
Reference Projects
For further learning resources and materials to kickstart your Godspeed development journey, please clone the gs-node-templates repository. This repository contains following examples for now.
- hello_world
- Full stack React based application
- Loan Origination System - the most complex example with fintech usecase
- Before running the LOS code, do read its setup.md file
Detailed Walkthrough & Playlist
Walkthrough
A walkthough on a Godspeed project with Loan Origination System example
Detailed Explainer Playlist
There is more
For the sake of brevity this section does not include every feature of Godspeed. But feel free to browse the documentatin for more insights and gems!