Fusio

Simply build and
manage REST APIs

Fusio is an open source API management platform which helps to build and manage REST APIs. Fusio provides all tools to quickly build an API from different data sources yet it is possible to create complete customized responses.

Deployment

Fusio uses a simple YAML format to describe the capabilities of the API. The following definition can be deployed through a simple command: /fusio/bin system:deploy.

routes:
  /news:
    methods:
      GET:
        public: true
        response: ResponseSchema
        action: EndpointAction
schema:
  ResponseSchema: !include resource/news/response.json
action:
  EndpointAction:
    class: Fusio\Custom\Action\AcmeAction
    config:
      connection: DevConnection
connection:
  DevConnection:
    class: Fusio\Adapter\Sql\Connection\Sql
    config:
      type: pdo_mysql
      host: 127.0.0.1
      username: root
      database: fusio
<?php

namespace Fusio\Custom\Action;

use Fusio\Engine\ActionAbstract;
use Fusio\Engine\ContextInterface;
use Fusio\Engine\Form\BuilderInterface;
use Fusio\Engine\Form\ElementFactoryInterface;
use Fusio\Engine\ParametersInterface;
use Fusio\Engine\RequestInterface;

class AcmeAction extends ActionAbstract
{
    public function handle(RequestInterface $request, ParametersInterface $configuration, ContextInterface $context)
    {
        /** @var \Doctrine\DBAL\Connection $connection */
        $connection = $this->connector->getConnection('DevConnection');

        $totalCount = (int) $connection->fetchColumn('SELECT COUNT(*) FROM acme_news');
        $result     = $connection->fetchAll('SELECT id, title, content, insertDate FROM acme_news ORDER BY insertDate DESC');

        return $this->response->build(200, [], [
            'totalCount' => $totalCount,
            'entry'      => $result,
        ]);
    }
}
{
    "type": "object",
    "properties": {
        "totalResults": {
            "type": "integer"
        },
        "entry": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "title": {
                        "type": "string"
                    },
                    "content": {
                        "type": "string"
                    },
                    "insertDate": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            }
        }
    }
}

Features

Once the API is deployed Fusio provides the following features out of the box:

build

API management

Fusio provides a powerful backend app to control and monitor your API.

assessment

Developer portal

Fusio provides a developer portal app where developer can register to use your API.

book

Documentation

Fusio provides a documentation app which shows all available API endpoints.

layers

JSON Schema

Fusio validates all incoming requests accordingly to the provided JSON schema.

account_box

OAuth2 authorization

App developer can obtain an access token to access non-public API endpoints.

swap_horiz

Rate limiting

Fusio provides a way to rate limit requests based on the user or app.

cloud_queue

Schema generation

Fusio provides an endpoint to automatically generate RAML and OAI specifications.

device_hub

JWT

For SPAs users can request a JWT to access protected parts of the API.

label_outline

Scope handling

Each user and app can be limited to scopes to request only specific parts of the API.

Development

Fusio provides a V8 action to develop the API endpoint logic (serverless) in javascript. In the following we show some common use cases and how to implement them with a few lines of javascript. Please take a look at the V8-API documentation to see a complete overview of all available functions.

var connection = connector.get('mysql-connection');
var row = connection.fetchAssoc('SELECT * FROM acme_news WHERE id = :id', {
    id: request.getUriFragment("id")
});

if (row) {
    response.setBody(row);
} else {
    response.setStatusCode(404);
    response.setBody({
        success: false,
        message: "Entry not found"
    });
}
var connection = connector.get('mysql-connection');
var body = request.getBody();

if (body.title && body.content) {
    var sql = 'INSERT INTO acme_news 
                       SET title = :title, 
                           content = :content, 
                           insertDate = NOW()';
    
    var row = connection.executeUpdate(sql, {
        title: body.title,
        content: body.content
    });

    response.setStatusCode(201);
    response.setBody({
        success: true,
        message: "Entry successful created"
    });
} else {
    response.setStatusCode(400);
    response.setBody({
        success: false,
        message: "Invalid request data"
    });
}
var connection = connector.get('http-connection');
var resp = connection.request("GET", "/old/api");

if (resp.getStatusCode() === 200) {
    var data = JSON.parse(resp.getBody());

    response.setStatusCode(200);
    response.setBody(data);
} else {
    response.setStatusCode(500);
    response.setBody({
        success: false,
        message: "Internal server error"
    });
}
var connection = connector.get('amqp-connection');
var body = request.getBody();

connection.basicPublish('acme_queue', body);

response.setStatusCode(202);
response.setBody({
    success: true,
    message: "Inserted message to queue"
});
var connection = connector.get('mongodb-connection');
var row = connection.findOne("acme_news", {
    id: request.getUriFragment("id")
});

if (row) {
    response.setBody(row);
} else {
    response.setStatusCode(404);
    response.setBody({
        success: false,
        message: "Entry not found"
    });
}
var connection = connector.get('mongodb-connection');
var body = request.getBody();

if (body.title && body.content) {
    var row = connection.insertOne("acme_news", {
        title: body.title,
        content: body.content
    });

    response.setStatusCode(201);
    response.setBody({
        success: true,
        message: "Entry successful created"
    });
} else {
    response.setStatusCode(400);
    response.setBody({
        success: false,
        message: "Invalid request data"
    });
}