Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] (feat: api-gateway): Smithy-like syntax and Velocity-Template DSL for Api Gatewau #111

Closed
wants to merge 2 commits into from

Conversation

sam-goodwin
Copy link
Owner

Excited with where this change is going! A total re-work of the API Gateway stuff and preparation for AppSync/GraphQL.

Closes #110

The idea is to entirely abstract VTL transformation done by API Gateway as ordinary function calls and data operations. Let's look at an example.

First, define some record types.

class GetUserRequest extends Record({
  userId: string
}) {}
class GetUserResponse extends Record({
  userId: string,
  userName: string
}) {}

Create a Service and an Endpoint:

// endpoint hosted in a Lambda Function
const endpoint = new Api.Endpoint(..);

const GameService = new Api.Service({
  serviceName: 'game-service',
});

Create a callable API hosted in our Lambda Endpoint.

const GetUserHandler = new Api.Call({
  endpoint,
  input: GetUserRequest,
  output: GetUserResponse
}, async request => Ok(new GetUserResponse({
  userId: request.userId,
  userName: 'user name'
})));

Add an "Operation" to the service (static function call, not resourceful yet):

GameService.addOperation('GetUser', GetUserRequest,
  request => GetUserHandler.call(request));

This operation accepts a GetUserRequest and returns a GetUserResponse by proxying the call to the Lambda Function.

What if the lambda only accepted a string instead of a GetUserRequest? We can express VTL transformation in a very simple, type-safe way:

GameService.addOperation('GetUser', GetUserRequest,
  // request.userId will synthesize a VTL transformation that extracts the userId key from the JSON payload received as a body
  request => GetUserHandler.call(request.userId));

Same is true for the output of an API integration:

GameService.addOperation('GetUser', GetUserRequest,
  // this time, both the input and output is transformed with VTL.
  // the output template will extract the userName field from the GetUserResponse returned by the Lambda integration
  request => GetUserHandler.call(request.userId).userName);

Where this really starts to shine is with service proxies like DynamoDB or SQS:

const queue = new SQS.Queue(..);
GameService.addOperation('SendMessage', string, s => queue.sendMessage(s));

const table = new DynamoDB.Table(..);
GameService.addOperation('PutItem', string, s => table.put(VTL.Record({
  id: s
}));

So far, we've only configured static operations on the API. Taking inspiration from Smithy, you can also add resources to the service:

const User = GameService.addResource({
  name: 'user',
  identifiers: {
    userId: string
  }
});

And then configure operations for get, create, update and list:

User.onGet(GetUserRequest, request => GetUserHandler.call(request));

mxro added a commit to mxro/punchcard that referenced this pull request Dec 9, 2021
Just fixing the links here. Was the example for the API gateway removed? Was looking around the project to find docs about using API gateway but couldn't find much - I think this was being reworked eg sam-goodwin#111?
@mxro mxro mentioned this pull request Dec 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Smithy Abstraction for API Gateway
1 participant