ALPS Helper Library

19th December 2020

Hi :).

The new ALPS Converter I developed makes it possible to convert an ALPS specification (spec short) to OpenApi, GraphQL or other APIs.

import { Alps, FormatType } from 'alps-unified-ts';

// loaded from a YAML file
Alps.unified(Alps.loadYaml('todo-alps.yaml'), { formatType: FormatType.OPENAPI })

Other great features of my ALPS unified library are:

  • automatic versioned releasing to NPM, PyPi, Maven and Nuget (for .NET).
  • Type support

The GitHub project were created using Projen. I will discuss what the ALPS Api and Projen is in more details in the next sections.

ALPS API

ALPS is a specification for describing the context of a service. ALPS can be used as specification input to generate low abstracted specifications like OpenApi / Swagger, WSDL, RAML, WADL.

The ALPS Converter converts an ALPS Api Spec into lower abstracted Api specifications. An example of such a conversion follows in the next section.

ALPS API Spec Example

The following example is a simple TODO ALPS API Spec.

alps:
  version: '1.0'
  doc:
    value: 'Simple Todo list example'

  ####################################
  # metadata
  ext:
    - type: metadata
      name: title
      value: simpleTodo
      tags: 'oas'
    - type: metadata
      name: id
      value: http://alps.io/profiles/mamund/simpleTodo
      tags: 'oas'
    - type: metadata
      name: root 
      value: http://api.example.org/todo
      tags: 'oas'
  
  descriptor:
    # properties
    # - these are the data elements
    - id: id
      type: semantic
      text: storage id of todo item
      
    - id: body
      type: semantic
      text: content of todo item

    # groupings
    # - these are the storage objects
    - id: todoItem
      type: group
      text: todo item
      descriptor:
      - href: '#id'
      - href: '#body'

    # actions
    # - these are the operations
    - id: todoList
      type: safe
      rt: todoItem
      text: return list of todo items
            
    - id: todoAdd
      type: unsafe
      rt: todoItem
      text: create a new todo item
      descriptor:
      - href: '#todoItem'
      
    - id: todoRemove
      type: idempotent
      tags: delete
      rt: todoItem
      text: remove a single todo item
      descriptor:
      - href: '#id'

The element todoItem consists of an id and a todo string body . Three actions are defined todoList to list the todo items, todoAdd to insert new todos and todoRemove to delete todo items.

From these, the Unified Convertor can generate this OpenApi specification:

openapi: 3.0.1

# *******************************************************************
# generated by "unified" from src/todo-alps.yaml
# date: Wed Nov 25 2020 18:47:05 GMT+0100 (Central European Standard Time)
# http://github.com/mamund/2020-11-unified
# *******************************************************************

info:
  title: simpleTodo
  description: Simple Todo list example
  version: 1.0.0

servers:
- url: 'http://api.example.org/todo'

paths:
  /todoList:
    get:
      summary: 'return list of todo items'
      operationId: todoList
      responses:
        200:
          description: todoList
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/todoItem'
  /todoAdd:
    post:
      summary: 'create a new todo item'
      operationId: todoAdd
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/todoItem'
      responses:
        200:
          description: add todoAdd
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/todoItem'
  /todoRemove/{id}:
    delete:
      summary: 'remove a single todo item'
      operationId: todoRemove
      parameters:
        - name: id
          in: path
          description: id of todoRemove
          required: true
          schema:
            type: string
      responses:
        204:
          description: delete todoRemove

components:
  schemas:
    todoItem:
      description: todo item
      type: object
      properties:
          id:
            type: string
            example: 4572
          body:
            type: string
            example: jn1ov7axj4kv560d0921xf

Or in GraphQL schema:

# *******************************************************************
# generated by "unified"
# date: Fri Dec 11 2020 16:51:00 GMT+0100 (Central European Standard Time)
# http://github.com/mamund/2020-11-unified
# *******************************************************************

type todoItem {
  id: String!
  body: String!
}

type Query {
  todoList: [todoItem]
}

type Mutation {
  todoAdd(todoItem: String!): todoItem
  todoRemove(id: String!): todoItem
}

schema {
  query: Query,
  mutation: Mutation
}

Projen

Projen allows sophisticated management of project configuration files through code. With just a few lines of TypeScript code, an entire repository can be configured. Here is an example:

const { JsiiProject } = require('projen');

const project = new JsiiProject({
  name: 'alps-unified-ts',
  authorAddress: 'damadden88@googlemail.com',
  authorName: 'Martin Mueller'
});

project.synth();

These few lines create all the GitHub project files your heart desires. Among them the package.json, .gitignore, tsconfig.json and many many more.

What's really cool is that Projen also comes with GitHub workflows that can publish new versions to registries like NPM or PYPI.

I fell in love with the Projen framework as it is a great abstraction and default for a setup of projects. I encourage you to give Projen a try and very soon you will experience the beauty of this framework yourself.

ALPS Library in Action

Here I would like to briefly introduce my new ALPS Unified Library. The TypeScript package can be used like this

import { Alps, FormatType } from 'alps-unified-ts';

// loaded from a YAML file
Alps.unified(Alps.loadYaml('./spec/todo-alps.yaml'), { formatType: FormatType.OPENAPI })

// or directly via TypeScript Object
Alps.unified(Alps.spec({
    alps: {
      version: '1.0',
      doc: {
        value: 'Simple Todo list example',
      },
      ...
    }
});

The Alps.unified(...) function always returns a string. Depending on the formType the returned string contains the desired format. In our example this is FormType.OPENAPI which is OpenApi in YAML. If you would now like to have OpenAPI returned in JSON, FormatType.OPENAPI_JSON would also work. For rendering the Graph QL schema you would have to use FormatType.DSL.

In Python, the library can be used like this:

import alps_unified_ts as alps

alps_def = alps.AlpsDef(
  version='1.0', 
  descriptor=[alps.DescriptorDef(id="id", type="semantic", text="sotrage id of todo item")], 
  doc=alps.DocDef(
    value="Simple Todo list example"), 
    ext=[
      alps.ExtDef(
        name="root", 
        tags="oas" 
        type="metadata", 
        value="http://api.example.org/todo"),
      alps.ExtDef(
        name="title", 
        tags="oas" 
        type="metadata", 
        value="simpleTodo")])

alps_converted = alps.Alps.unified(alps_document=alps.Alps.spec(alps=alps_def), format_type=alps.FormatType.OPENAPI)

Using it in Java and .NET should look similar.

In my previous blogpost ALPS combined with CDK, I explain how to optionally create an AWS Api Gateway or AWS Appsync from an ALPS Spec using the ALPS Todo example and the ALPS unified library.

Summary

Building a library with Projen was super fun! I used it to build a new, improved version of the alps unified library. It now comes with super cool new features that I introduced here.

By the way, one more info. If you are also interested in the ALPS topic, with the ALPS Community we regularly organize community meetings online. There you can meet exciting people from all over the world. Feel free to come by :) .

To the wonderful readers of this article I'm saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as Twitter or FaceBook. Thank you very much :).

I love to work on Content Management Open Source projects. A lot from my stuff you can already use on www.github.com/mmuller88 . If you like my work there and my blog posts, please consider supporting me on Patreon:

Become a Patreon!

Share