All Projects → FujitsuLaboratories → escapin

FujitsuLaboratories / escapin

Licence: MIT license
Escapin is a JS/TS transpiler for escaping from complicated usage of cloud services and APIs

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to escapin

serverless-web-app-example
Serverless React Web App Example
Stars: ✭ 41 (+105%)
Mutual labels:  serverless-framework
ShenScript
Shen for JavaScript
Stars: ✭ 40 (+100%)
Mutual labels:  transpiler
serverless-dynamodb-ttl
⚡️ Serverless Plugin to set DynamoDB TTL
Stars: ✭ 16 (-20%)
Mutual labels:  serverless-framework
bingo
一个基于golang的serveless 的低代码平台。可以快速的构建基于微服务和数据库的管理类应用。内置了权限、流程、表单引擎等基础功能。
Stars: ✭ 52 (+160%)
Mutual labels:  serverless-framework
serverless-media-portal
Ready-to-deploy webapp for sharing home videos: a React frontend with a AWS Lambda backend using FFmpeg to process videos. Created using Serverless Framework.
Stars: ✭ 90 (+350%)
Mutual labels:  serverless-framework
sugartex
SugarTeX is a more readable LaTeX language extension and transcompiler to LaTeX. Fast Unicode autocomplete in Atom editor via https://github.com/kiwi0fruit/atom-sugartex-completions
Stars: ✭ 74 (+270%)
Mutual labels:  transpiler
forum
Serverless Frameworkの日本語フォーラムです
Stars: ✭ 38 (+90%)
Mutual labels:  serverless-framework
awesome-serverless-framework
Serverless Framework 开发资源汇总 🚀
Stars: ✭ 120 (+500%)
Mutual labels:  serverless-framework
go-mlog
Go to Mindustry (MLOG) compiler, runtime and decompiler (WIP)
Stars: ✭ 19 (-5%)
Mutual labels:  transpiler
serverless-aws-rust-http
⚡🏗️ template for new aws lambda serverless rust http apps
Stars: ✭ 85 (+325%)
Mutual labels:  serverless-framework
LunarML
A Standard ML compiler that produces Lua/JavaScript
Stars: ✭ 127 (+535%)
Mutual labels:  transpiler
json-sql-builder2
Level Up Your SQL-Queries
Stars: ✭ 59 (+195%)
Mutual labels:  transpiler
serverless-side-rendering-vue-nuxt
Sample project for using Nuxt.js to create a server-side rendered Vue.js app on AWS Lambda and AWS API Gateway.
Stars: ✭ 109 (+445%)
Mutual labels:  serverless-framework
War3Net
A .NET implementation of Warcraft III related libraries.
Stars: ✭ 76 (+280%)
Mutual labels:  transpiler
amazon-ivs-chime-web-demo
A demo web application intended as an educational tool for demonstrating how to load and play Amazon IVS streams alongside the Amazon Chime SDK.
Stars: ✭ 35 (+75%)
Mutual labels:  serverless-framework
habrlang
Step by Step guide how to make your own programming language
Stars: ✭ 20 (+0%)
Mutual labels:  transpiler
telegram-stepfunctions-bot
Serverless Telegram bot made on 4 AWS Lambda chained by AWS Step Functions. All of this written on Serverless Framework using plugins.
Stars: ✭ 26 (+30%)
Mutual labels:  serverless-framework
serverless data pipeline example
Build and Deploy A Serverless Data Pipeline on AWS
Stars: ✭ 24 (+20%)
Mutual labels:  serverless-framework
desktop
A native GUI application that makes it easy to explore and test Serverless Framework applications built on AWS Lambda.
Stars: ✭ 42 (+110%)
Mutual labels:  serverless-framework
serviceless
[DEPRECATED] Cli tool on top of Serverless framework
Stars: ✭ 22 (+10%)
Mutual labels:  serverless-framework

Escapin

the transpiler for escaping from complicated usage
of cloud services and APIs

npm version Build Status Renovate enabled codecov code style: prettier semantic-release MIT License

Table of Contents

Prerequisites

  1. Node.js 10.x or later
  2. Serverless Framework

Installation

npm install --save-dev escapin

Usage

Escapin provides CLI escapin that works on Node.js project directories containing ./package.json.

First, append the following scripts in package.json:

{
  "scripts": {
    "build": "escapin",
    "start": "cd build && serverless deploy"
  }
}

Then, run build and start on the project folder:

npm run build
npm start

Escapin transpiles your source code into executable one as a serverless application, and generates serverless.yml that can be used for deploying the programs to cloud services by Serverless Framework.

CLI options

Usage: escapin [options]

Options:
  -V, --version         output the version number
  -d, --dir <dir>       working directory (default: ".")
  --ignore-path <path>  specify path of ignore file (default: ".gitignore")
  -h, --help            output usage information

Configuration

You can give configuration information to Escapin CLI by using the following ways:

Place Format
escapin property in package.json JSON
.escapinrc JSON or YAML
.escapinrc.json JSON
.escapinrc.yaml or .escapinrc.yml YAML
.escapinrc.js or escapin.config.js JavaScript

Here is the example of JSON configuration file .escapinrc.

{
  "name": "sendmail",
  "api_spec": "swagger.yaml",
  "credentials": [{ "api": "mailgun API", "basicAuth": "api:<YOUR_API_KEY>" }],
  "platform": "aws",
  "default_storage": "table",
  "output_dir": "build",
  "http_client": "axios"
}
module.exports = {
  name: "sendmail",
  api_spec: "swagger.yaml",
  credentials: [{ api: "mailgun API", basicAuth: "api:<YOUR_API_KEY>" }],
  platform: "aws",
  default_storage: "table",
  output_dir: "build",
  http_client: "axios",
};
Name Description Options Default
name name of the application
api_spec path of the specification file of the API published by the application
credentials credentials required in calling external APIs
platform cloud platform where the application is being deployed aws aws
default_storage the storage type that are selected by default table
bucket
table
output_dir directory where the transpilcation artifacts are being stored build
http_client http client used in generated code for requesting apis defined by OAS axios
request
axios

Transpilation features


Storage

You can use several kinds of storage services just like a first-class object in JavaScript. By declaring an empty object placing a special type annotation (e.g., bucket) you can create a resource in that type of storage services.

You can use both canonical type platform.storageType (e.g., aws.bucket) and shorthand type storageType (e.g., bucket) for storage objects; platform in the configuration file is used in shorthand types. If you omit a type annotation, default_storage is used as that type by default. In v0.2.x, bucket and table is available for storage types; bucket represents a bucket in object storage, and table represents a table in NoSQL datastore service.

export const foo: aws.bucket = {}; // AWS S3 Bucket
export const bar: bucket = {}; // AWS S3 Bucket
export const baz: table = {}; // AWS DynamoDB Table
export const qux = {}; // AWS DyanmoDB Table

Here are the usage example of storage objects:

export const foo: bucket = {};

foo[id] = bar; // uploading data
baz = foo[id]; // downloading data
qux = Object.keys(foo); // obtaining keys of data
delete foo[id]; // deleting existing data

Input


index.js
export const foo: table = {};

foo[id] = bar;
.escapinrc.js
module.exports = {
  platform: "aws",
  ...
};

Output


index.js
import { DynamoDB } from "aws-sdk";

await new Promise((resolve, reject) => {
  new DynamoDB().putItem(
    {
      TableName: "foo-9fe932f9-32e7-49f7-a341-0dca29a8bb32",
      Item: {
        key: { S: id },
        type: { S: typeof bar },
        value: {
          S:
            typeof bar === "object" || typeof bar === "function"
              ? JSON.stringify(bar)
              : bar,
        },
      },
    },
    (err, _temp) => {
      if (err) {
        reject(err);
      } else {
        resolve(_temp);
      }
    }
  );
});
serverless.yml
resources:
  Resources:
    fooTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: foo-9fe932f9-32e7-49f7-a341-0dca29a8bb32
        KeySchema:
          - AttributeName: key
            KeyType: HASH
        AttributeDefinitions:
          - AttributeName: key
            AttributeType: S
        ProvisionedThroughput:
          ReadCapacityUnits: 5
          WriteCapacityUnits: 5
    escapinFunctionRole:
      Properties:
        Policies:
          - PolicyName: foo-9fe932f9-32e7-49f7-a341-0dca29a8bb32-FullAccess
            PolicyDocument:
              Version: "2012-10-17"
              Statement:
                - Effect: Allow
                  Action:
                    - "dynamodb:ListGlobalTables"
                    - "dynamodb:ListTables"
                  Resource: "*"
                - Effect: Allow
                  Action: "dynamodb:*"
                  Resource:
                    "Fn::GetAtt":
                      - fooTable
                      - Arn

Function


Input


index.js
export function handler(req) {
  if (errorOccured()) {
    throw new Error("[400] An error occured");
  }

  return { message: "Succeeded" };
}
.escapinrc.js
module.exports = {
  name: "myapp",
  platform: "aws",
  api_spec: "swagger.yaml",
  ...
};
swagger.yaml
swagger: "2.0"
info:
  version: "1.0.0"
  title: "myapp"
host: "myapp.org"
basePath: "/v1"
schemes:
  - "http"
produces:
  - "application/json"
paths:
  /handle:
    get:
      summary: "handler"
      x-escapin-handler: "index.handler"
      parameters: []
      responses:
        200:
          schema:
            $ref: "#/definitions/Message"
        400:
          schema:
            $ref: "#/definitions/Error"
  ...

Output


index.js
export function handler(req, context, callback) {
  if (errorOccured()) {
    callback(new Error("[400] An error occured."));
    return;
  }

  callback(null, { message: "Succeeded" });
  return;
}
serverless.yml
functions:
  handlerFunction:
    handler: index.handler
    runtime: nodejs10.x
    role: escapinFunctionRole
    events:
      - http:
          path: handle
          method: get
          cors: true
          integration: lambda
resources:
  Resources:
    escapinFunctionRole:
      Type: "AWS::IAM::Role"
      Properties:
        Path: /escapin/
        RoleName: myappEscapinFunctionRole
        AssumeRolePolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - lambda.amazonaws.com
              Action: "sts:AssumeRole"
        Policies: ...

Importing open APIs


Usage

import api from "http://path/to/swagger.yaml";
Method Path Header Body Example
GET /items items = api.items;
GET /items/:id item = api.items[id];
GET /items/:id/props props = api.items[id].props;
GET /items/:id?foo=bar item = api.items[id] [ { foo: 'bar' } ] ;
GET /items/:id?foo=bar baz: qux item = api.items[id] [ { foo: 'bar', baz: 'qux' } ] ;
POST /:domain/messages { quux: 'corge' } api.domain[domain].messages ( { quux: 'corge' } ) ;
POST /items { quux: 'corge' } api.items ( { quux: 'corge' } ) ;
POST /items/:id?foo=bar baz: qux { quux: 'corge' } api.items[id] [ { foo: 'bar', baz: 'qux' } ] ( { quux: 'corge' } ) ;
PUT /items/:id baz: qux { quux: 'corge' } api.items[id] [ { baz: 'qux' } ] = { quux: 'corge' };
DELETE /items/:id delete api.items[id];

Input


index.js
import api from "http://path/to/swagger.yaml";
api.items[id][{ foo: "bar", baz: "qux" }]({ quux: "corge" });
.escapinrc.js
module.exports = {
  http_client: "request",
  ...
};
http://path/to/swagger.yaml
swagger: "2.0"
info:
  title: Awesome API
  description: An awesome API
  version: "1.0.0"
host: "api.endpoint.com"
schemes:
  - http
basePath: /v1
produces:
  - application/json
consumes:
  - application/json
paths:
  /items/{id}:
    post:
      description: Do some task regarding an item
      parameters:
        - name: id
          in: path
          type: string
          required: true
          description: Item ID
        - name: foo
          in: query
          type: string
          required: true
        - name: baz
          in: header
          type: string
          required: true
        - name: params
          in: body
          schema:
            $ref: "#/definitions/Params"
      responses:
        "200":
          description: Succeeded
          schema:
            $ref: "#/definitions/Message"
definitions:
  Params:
    type: object
    properties:
      quux:
        type: string
  Message:
    type: object
    properties:
      message:
        type: string

Output


index.js
import request from "request";
const { _res, _body } = request({
  uri: `http://api.endpoint.com/v1/items/${id}`,
  method: "post",
  contentType: "application/json",
  json: true,
  qs: {
    foo: "bar",
  },
  headers: {
    baz: "qux",
  },
  body: {
    quux: "corge",
  },
});

Publishing your API


Input


index.js
export function handleItem(req) {
  const id = req.path.id;
  const foo = req.query.foo;
  const baz = req.header.baz;
  const quux = req.body.quux;

  if (errorOccured()) {
    throw new Error("[400] An error occured.");
  }

  return { message: "Succeeded" };
}
swagger.yaml
swagger: "2.0"
info:
  title: Awesome API
  description: An awesome API
  version: "1.0.0"
host: "api.endpoint.com"
schemes:
  - https
basePath: /v1
produces:
  - application/json
consumes:
  - application/json
paths:
  /items/{id}:
    post:
      x-escapin-handler: index.handleItem
      description: Do some task regarding an item
      parameters:
        - name: id
          in: path
          type: string
          required: true
          description: Item ID
        - name: foo
          in: query
          type: string
          required: true
        - name: baz
          in: header
          type: string
          required: true
        - name: params
          in: body
          schema:
            $ref: "#/definitions/Params"
      responses:
        "200":
          schema:
            $ref: "#/definitions/Message"
        "400":
          schema:
            $ref: "#/definitions/Error"
definitions:
  Params:
    type: object
    properties:
      quux:
        type: string

Output


index.js
export function handleItem(req, context, callback) {
  const id = req.path.id;
  const foo = req.query.foo;
  const baz = req.header.baz;
  const quux = req.body.quux;

  if (errorOccured()) {
    callback(new Error("[400] An error occured."));
    return;
  }

  callback(null, { message: "Succeeded" });
  return;
}
serverless.yml
functions:
  handleItemFunction:
    handler: index.handleItem
    runtime: nodejs10.x
    role: escapinFunctionRole
    events:
      - http:
          path: 'items/{id}'
          method: post
          cors: true
          integration: lambda
  ...

Auto-completing asynchronous features


Destructuring nesting callbacks


Original
function func() {
  call(arg, (err, data1, data2) => {
    if (err) {
      handleError(err);
    } else {
      doSomething(data1, data2);
    }
  });
}

Destructured
function func() {
  try {
    const { data1, data2 } = call(arg);
    doSomething(data1, data2);
  } catch (err) {
    handleError(err);
  }
}

Asynchronized
async function func() {
  try {
    const _data = await new Promise((resolve, reject) => {
      call(arg, (err, _data1, _data2) => {
        if (err) reject(err);
        else resolve({ _data1, _data2 });
      });
    });
    doSomething(_data._data1, _data._data2);
  } catch (err) {
    handleError(err);
  }
}

for, for-in, for-of (collection should be obtained asynchronously)


Input
for (const item of api.call(arg)) {
  doSomething(item);
}

Output
const _data = await new Promise((resolve, reject) => {
  api.call(arg, (err, data) => {
    if (err) reject(err);
    else resolve(data);
  });
});
for (const item of _data) {
  doSomething(item);
}

for, for-in, for-of (executable in parallel)


Input
for (const arg of args) {
  api.call(arg);
}

Output
const _promises = [];
for (const arg of args) {
  _promises.push(
    (async () => {
      await new Promise((resolve, reject) => {
        api.call(arg, (err, data) => {
          if (err) reject(err);
          else resolve(data);
        });
      });
    })()
  );
}
await Promise.all(_promises);

for, for-in, for-of (NOT executable in parallel)


Input
let sum = 0;
for (const arg of args) {
  sum += api.call(arg);
}

Output
let sum = 0;
for (const arg of args) {
  const _data = await new Promise((resolve, reject) => {
    api.call(arg, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
  sum += _data;
}

while,do-while


Input
while ((data = api.call(arg)) === null) {
  doSomething(data);
}

Output
let _data = await new Promise((resolve, reject) => {
  api.call(arg, (err, data) => {
    if (err) reject(err);
    else resolve(data);
  });
});
while ((data = _data) === null) {
  doSomething(data);
  _data = await new Promise((resolve, reject) => {
    api.call(arg, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
}

if-else


Input
if (api.call(arg)) {
  doSomething();
} else if (api.call2(arg)) {
  doSomething2();
}

Output
const _data = await new Promise((resolve, reject) => {
  api.call(arg, (err, data) => {
    if (err) reject(err);
    else resolve(data);
  });
});
if (_data) {
  doSomething();
} else {
  let _data2 = await new Promise((resolve, reject) => {
    api.call2(arg, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
  if (_data2) {
    doSomething2();
  }
}

switch-case


Input
switch (api.call(arg)) {
  case "foo":
    api.call2(arg);
    break;
  case "bar":
    api.call3(arg);
    break;
  default:
    break;
}

Output
let _promise;
const _data = await new Promise((resolve, reject) => {
  api.call(arg, (err, data) => {
    if (err) reject(err);
    else resolve(data);
  });
});
switch (_data) {
  case "foo":
    await new Promise((resolve, reject) => {
      api.call2(arg, (err, data) => {
        if (err) reject(err);
        else resolve(data);
      });
    });
    break;
  case "bar":
    await new Promise((resolve, reject) => {
      api.call3(arg, (err, data) => {
        if (err) reject(err);
        else resolve(data);
      });
    });
    break;
  default:
    break;
}

functions that require callback functions as an argument (e.g., Array#forEach)


Input
// special rules are applied for Array#map and Array#forEach
args.map((arg) => api.call(arg));
args.forEach((arg) => api.call(arg));

args.some((arg) => api.call(arg));

Output
import deasync from "deasync";

await Promise.all(args.map(async (arg) => await api.call(arg)));
args.forEach(async (arg) => await api.call(arg));

args.some((arg) => {
  let _data;
  let done = false;
  new Promise((resolve, reject) => {
    api.call(arg, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  }).then((data) => {
    _data = data;
    done = true;
  });
  deasync.loopWhile((_) => !done);
  return _data;
});

asynchronous features appearing in input


Input
args.map(arg => await promisifiedFunc(arg));

Output
await Promise.all(args.map(async (arg) => await promisifiedFunc(arg)));

Publications

License

MIT

FOSSA Status

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].