Common API Documentation
JSON Response Builder
Building Successful JSON Response
include TreatanyoneCommonApi::JsonResponseBuilder
def index(event:,context:)
posts = Post.all
(posts)
end
Building Error JSON Response
When handling errors, this will also log it to CloudWatch logs, useful when debugging errors.
def index(event: context:)
#...
rescue => e
error_handling(:internal_server_error, e.message)
end
Supported HTTP status codes
- :continue
- :switching_protocols
- :processing
- :early_hints
- :ok
- :created
- :accepted
- :non_authoritative_information
- :no_content
- :reset_content
- :partial_content
- :multi_status
- :already_reported
- :im_used
- :multiple_choices
- :moved_permanently
- :found
- :see_other
- :not_modified
- :use_proxy
- :(unused)
- :temporary_redirect
- :permanent_redirect
- :bad_request
- :payment_required
- :forbidden
- :not_found
- :method_not_allowed
- :not_acceptable
- :proxy_authentication_required
- :request_timeout
- :conflict
- :gone
- :length_required
- :precondition_failed
- :payload_too_large
- :uri_too_long
- :unsupported_media_type
- :range_not_satisfiable
- :expectation_failed
- :misdirected_request
- :unprocessable_entity
- :locked
- :failed_dependency
- :too_early
- :upgrade_required
- :precondition_required
- :too_many_requests
- :request_header_fields_too_large
- :unavailable_for_legal_reasons
- :internal_server_error
- :not_implemented
- :bad_gateway
- :service_unavailable
- :gateway_timeout
- :http_version_not_supported
- :variant_also_negotiates
- :insufficient_storage
- :loop_detected
- :bandwidth_limit_exceeded
- :not_extended
- :network_authentication_required
Strong Parameters
Same strong parameters came from Rails version 6. You need to use set_params
method to correctly map hash coming from request payload.
Example Usage:
def handler(event:, context:)
set_params(event, root_key: :task)
task = Task.new(task_params)
end
#...
private
def task_params
_params.require(:task).permit(:client_id, :due_date, :task_type, :details, :practitioner_id, :active)
end
Handler
The advantage of using this handle
method to create the greet
method is that, handle
transforms the event object to a Request object for easier handling of data. It also includes rescue blocks, that catches common errors and exceptions, and handle appropriate responses so you dont have to explicitly define rescue clauses when creating handler methods.
Example:
serverless.yml
:
functions:
sampleFunction:
handler: sample_handler.SampleHandler.greet
events:
- http: GET /hello
sample_handler.rb
:
module SampleHandler
include TreatanyoneCommonApi::Handler
handle :greet do |request, context|
puts "Hello #{request.params[:name]}"
end
end
Terminal:
$ sls invoke local -f sampleFunction -d '{"body": {"name":"Sam Paul"} }'
$ Hello Sam Paul
Kinesis Data Stream Publish Event
Created a standardized way of publishing events to Kinesis Data Stream
task = Task.first
# This will be equivalent to current_user or the current session
user_id = User.first.id
# Additional data related to event
data = { foo: "bar" }
client = TreatanyoneCommonApi::Kinesis.new("TaskCreated", task, user_id, {
data: data,
# The Domain type of event (e.g.: Task)
aggregate_type: "Task"
})
# Sends the event to Kinesis Data Stream for processing
client.publish_event
Lambda Invocation
Created a standardized way of invoking lambda functions through SDK
As a helper method:
module ProviderBff
module Resolvers
class SomeType
include TreatanyoneCommonApi::Lambda
#...
def resolve
invocation_response = invoke_function(
# Lambda ARN or Function Name
function: "arn:aws:lambda:us-west-2:xxxxxxxx:function:some-service-function-name",
payload: JSON.generate({ foo: "bar" })
)
# Do something with payload_data
payload_data = JSON.parse(invocation_response.payload.read)
#...
end
end
end
end
As a class instance method (more configuration available):
# Region defaults to `us-west-2`
client = TreatanyoneCommonApi::Lambda::Client.new(region: "us-west-2")
client.invoke(
function_name: "LAMBDA_ARN_OR_NAME",
invocation_type: "RequestResponse",
log_type: "None",
client_context: "user_1234",
payload: JSON.generate({foo: "bar"}),
qualifier: nil
)
lambda_payload = client.lambda_payload
Invocation Types
- Event
- RequestResponse (default)
- DryRun
Log Types
- None (default)
- Tail
Using Kinesis Publish and Invocation
It is important to always Publish your events before invoking a function, this will keep all events recorded via Audit Trail.
Example:
module ProviderBff
module Resolvers
class SomeType
include TreatanyoneCommonApi::Lambda
#...
def resolve(id)
task = Task.find(id)
# This will be equivalent to current_user or the current session
user_id = current_user.id
# Additional data related to event
data = { foo: "bar" }
client = TreatanyoneCommonApi::Kinesis.new("TaskCreated", task, user_id, {
data: data,
# The Domain type of event (e.g.: Task)
aggregate_type: "Task"
})
# Sends the event to Kinesis Data Stream for auditing
client.publish_event
invocation_response = invoke_function(
# Lambda ARN or Function Name
function: "arn:aws:lambda:us-west-2:xxxxxxxx:function:some-service-function-name",
payload: JSON.generate(data)
)
# Do something with payload_data
payload_data = JSON.parse(invocation_response.payload.read)
#...
end
end
end
end
Publishing gem
Added commands for local dev/testing
$ bin/setup
Starts up a docker container that runs a geminabox
instance (local rubygems). Access the page through http://localhost:9292
$ bin/console
Starts a terminal session with treatanyone_common_api
gem loaded for easier debugging and testing of functionalities.
$ rake publish:local
Build and publish gem to http://localhost:9292. Test with other repo (locally) by updating gemfile
# Another repo's Gemfile that uses treatanyone_common_api
source 'http://localhost:9292' do
gem 'treatanyone_common_api', '>= 0.4.1'
end
$ gem uninstall treatanyone_common_api # => uninstall previous version from remote
$ bundle install # Will install version from http://localhost:9292
Sending real-time notifications from backend to Websocket server:
Make sure to set ENV["WEBSOCKET_NOTIFY_ARN"]
on your serverless config to be able to connect to Websocket server
Parameters:
user_uuids
UUID of users to receive notifications (Users should be connected to the Websocket server to receive notifications)
notification
Hash containing metadata of the notification
include TreatanyoneCommonApi::Notifier
notify_users(user_uuids: ["ecfa7091-aab0-44fe-ba6d-9cb0b11012xx"], notification: {"message": "Hello World! This is a real time notification"})
Publishing SNS Events
require 'treatanyone_common_api'
module EspressoHandler
extend TreatanyoneCommonApi::Handler
Publisher = TreatanyoneCommonApi::Pubisher # Alias. Optional
Pubisher.topic_arn = ENV['SNS_TOPIC_ARN'] # SNS Topic arn
Pubisher.event_object = 'EspressoModel' # Prefer UpperCamelCase format
handle :create do |event, context|
beans = Bean.find_by_type(event.params[:bean_type])
.grind(:espresso)
.scoop
espresso = beans.brew(:double)
publish_response = Pubisher.created(espresso.as_json)
render(201, json: espresso)
end
handle :update do |event, context|
# ...
publish_response = Pubisher.updated(espresso.as_json)
render(200, json: espresso)
end
handle :delete do |event, context|
# ...
publish_response = Pubisher.deleted(espresso.as_json)
render(200, json: espresso)
end
end