DreamFactory provides the ability to create custom scripting services that can be invoked from the REST API. These can be written in JavaScript (V8js or Node.js) or PHP. You can use these services to implement business logic or combine multiple API calls into a single call. For example, if you have several databases you could access each one from the script and then combine the results as JSON or XML for return to the client.
Read more about DreamFactory's new features.
This blog post presents an example of creating a custom scripting service named ‘Math’ that implements a simple calculator. I’ll show you how to create the service and then how to create the OpenAPI (Swagger 2.0) service definition for that service. The OpenAPI spec provides a portable service definition format and allows you to use the API Docs in the DreamFactory admin console to test and explore your service.
Prerequisites
You'll need a DreamFactory instance running version 2.1.0 or later. To check the version go to the Config tab in the admin console and select System Info. Look for DreamFactory Version. Your instance needs to support server side scripting with V8js. The Bitnami installers support V8js scripting; our free hosted system does not.
Create a New Custom Scripting Service
var params, required, n1, n2, resource, result;var lodash = require("lodash.min.js");
if (event.request.method !== "GET") {
throw("Only HTTP GET is allowed on this service.");
}// get query params from request
params = event.request.parameters;// get resource, /math —> "", /math/add —> "add"
resource = event.resource;
if (resource !== "") {
// check for required params
required = ["n1","n2"];
lodash._.each( required, function( element ) {
if (!params.hasOwnProperty(element) || !params[element]) {
throw( "Missing '" + element + "' in params\n" );
}
});
n1 = Number(params.n1);
n2 = Number(params.n2);
}switch (resource) {
case "":
// /math means return all supported resources
result = {"resource": ["add", "subtract", "multiply", "divide"]};
break;
case "add":
result = {"result": n1 + n2};
break;
case "subtract":
result = {"result": n1 - n2};
break;
case "multiply":
result = {"result": n1 * n2};
break;
case "divide":
if (!n2) {
throw("Divide by zero error.");
}
result = {"result": n1 / n2};
break;
default:
throw("Invalid or missing resource name.");
break;
}return result;
Now you can call this service from the REST API. Using your REST client of choice, make the following GET request. Replace everything before /api/v2 with your instance base URL. You can use HTTP basic auth or pass an authenticated session token in the API call.
For example, with cURL:
curl -i -k -3 -X GET "https://127.0.0.1:8080/api/v2/math"
-H "X-DreamFactory-Session-Token: your-session-token"
The URL ends with the service name, ‘math’. Since there is no resource specified like add or subtract, the scripting service will return a list of available resources.
{
"resource": [
"add",
"subtract",
"multiply",
"divide"
]
}
To add two numbers, make the following request. Now the URL also includes the resource 'add'.
GET https://127.0.0.1:8080/api/v2/math/add?n1=3&n2=5
The script returns the sum of n1 and n2 in JSON format.
{
"result": 8
}
The script checks to make sure both n1 and n2 are specified. If not, an exception is thrown and an error returned to the client. This logic is implemented in the script for the service. How you design and code your services is completely up to you. Here's an example of an invalid request that is missing n2.
GET https://127.0.0.1:8080/api/v2/math/add?n1=3
{
"error": {
"context": null,
"message": "Missing 'n2' in params\n",
"code": 500
}
}
Creating a Swagger Service Definition
To turn up the awesomeness on your service you can create a Swagger service definition for it. This defines the inputs and outputs for the service and allows you to explore the service from the API Docs in the DreamFactory admin console, or any other Swagger-compliant tool. The first step is to go to the Swagger editor and click the 'try the live demo' link. Paste the following YAML into the editor. We provided this one for you for the Math service but you would build the YAML for your own services using this same editor.
swagger: '2.0'info:
version: "2.0"
title: "Math Service"parameters:
n1:
name: n1
in: query
description: First number
required: true
type: number
format: integer
n2:
name: n2
in: query
description: Second number
required: true
type: number
format: integerpaths:
/math:
get:
tags:
- math
description: Resources available to this service.
responses:
'200':
description: Success
schema:
$ref: '#/definitions/MathResourceList'
default:
description: Error
schema:
$ref: '#/definitions/MathError'
/math/add:
get:
tags:
- math
description: Add two numbers.
parameters:
- $ref: "#/parameters/n1"
- $ref: "#/parameters/n2"
responses:
'200':
description: Success
schema:
$ref: '#/definitions/MathSuccess'
default:
description: Error
schema:
$ref: '#/definitions/MathError'
/math/subtract:
get:
tags:
- math
description: Subtract two numbers.
parameters:
- $ref: "#/parameters/n1"
- $ref: "#/parameters/n2"
responses:
'200':
description: Success
schema:
$ref: '#/definitions/MathSuccess'
default:
description: Error
schema:
$ref: '#/definitions/MathError'
/math/multiply:
get:
tags:
- math
description: Multiply two numbers.
parameters:
- $ref: "#/parameters/n1"
- $ref: "#/parameters/n2"
responses:
'200':
description: Success
schema:
$ref: '#/definitions/MathSuccess'
default:
description: Error
schema:
$ref: '#/definitions/MathError'
/math/divide:
get:
tags:
- math
description: Divide two numbers.
parameters:
- $ref: "#/parameters/n1"
- $ref: "#/parameters/n2"
responses:
'200':
description: Success
schema:
$ref: '#/definitions/MathSuccess'
default:
description: Error
schema:
$ref: '#/definitions/MathError'
definitions:
MathResourceList:
type: object
properties:
resource:
type: array
description: Array of accessible resources available to this service.
items:
type: string
MathSuccess:
type: object
properties:
result:
type: integer
MathError:
type: object
properties:
code:
type: integer
format: int32
description: Error code.
message:
type: string
description: String description of the error.
Once the YAML is correct you should export it as Swagger JSON from the menu option Generate Client --> Swagger JSON. The output should look like this.
{
"swagger": "2.0",
"info": {
"version": "2.0",
"title": "Math Service"
},
"paths": {
"/math": {
"get": {
"tags": ["math"],
"description": "Resources available to this service.",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/MathResourceList"
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "#/definitions/MathError"
}
}
}
}
},
"/math/add": {
"get": {
"tags": ["math"],
"description": "Add two integers.",
"parameters": [{
"name": "n1",
"in": "query",
"description": "First number",
"required": true,
"type": "number",
"format": "integer"
}, {
"name": "n2",
"in": "query",
"description": "Second number",
"required": true,
"type": "number",
"format": "integer"
}],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/MathSuccess"
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "#/definitions/MathError"
}
}
}
}
},
"/math/divide": {
"get": {
"tags": ["math"],
"description": "Divide two integers.",
"parameters": [{
"name": "n1",
"in": "query",
"description": "First number",
"required": true,
"type": "number",
"format": "integer"
}, {
"name": "n2",
"in": "query",
"description": "Second number",
"required": true,
"type": "number",
"format": "integer"
}],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/MathSuccess"
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "#/definitions/MathError"
}
}
}
}
},
"/math/multiply": {
"get": {
"tags": ["math"],
"description": "Multiply two integers.",
"parameters": [{
"name": "n1",
"in": "query",
"description": "First number",
"required": true,
"type": "number",
"format": "integer"
}, {
"name": "n2",
"in": "query",
"description": "Second number",
"required": true,
"type": "number",
"format": "integer"
}],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/MathSuccess"
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "#/definitions/MathError"
}
}
}
}
},
"/math/subtract": {
"get": {
"tags": ["math"],
"description": "Subtract two integers.",
"parameters": [{
"name": "n1",
"in": "query",
"description": "First number",
"required": true,
"type": "number",
"format": "integer"
}, {
"name": "n2",
"in": "query",
"description": "Second number",
"required": true,
"type": "number",
"format": "integer"
}],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/MathSuccess"
}
},
"default": {
"description": "Error",
"schema": {
"$ref": "#/definitions/MathError"
}
}
}
}
}
},
"definitions": {
"MathResourceList": {
"type": "object",
"properties": {
"resource": {
"type": "array",
"description": "Array of accessible resources available to this service.",
"items": {
"type": "string"
}
}
}
},
"MathSuccess": {
"type": "object",
"properties": {
"result": {
"type": "integer"
}
}
},
"MathError": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32",
"description": "Error code."
},
"message": {
"type": "string",
"description": "String description of the error."
}
}
}
},
"parameters": {
"n1": {
"name": "n1",
"in": "query",
"description": "First number",
"required": true,
"type": "number",
"format": "integer"
},
"n2": {
"name": "n2",
"in": "query",
"description": "Second number",
"required": true,
"type": "number",
"format": "integer"
}
}
}
Open the downloaded zip file and copy the JSON from swagger.json. Paste it into the DreamFactory service definition editor and save it as part of your service. After that you can explore the service using the API Docs tab in the DreamFactory admin console. Here are the detailed steps.
To get a list of resources, click the first GET button then click Try it out!. It will show you the request URL and response data. To add two numbers click the GET button next to /math/add. Enter your two required numbers, n1 and n2, then click Try it out!. You get the same result as when using a REST client or calling from your app, but now you are using the UI that was automatically built from the Swagger definition that you created.
Now you can write your app that calls this service and use roles to control access to the service. To recap, we created a new custom scripting service and called it from a REST client to prove it was working. Then we created a Swagger service definition that allows us to explore the service from the API Docs UI. Finally, we used that UI to call the service. The custom scripting service and its service definition are portable and can be easily moved to other DreamFactory instances. We have more examples in the works, but this one should get you started creating and documenting your own custom scripting services with DreamFactory.
Read more about DreamFactory 2.1:
https://blog.dreamfactory.com/put-some-swagger-in-your-dreamfactory-custom-scripting-services/
https://blog.dreamfactory.com/dreamfactory-2-1-release-news/
https://blog.dreamfactory.com/dreamfactory-2-1-1-release/
https://blog.dreamfactory.com/dreamfactory-2-1-2-release/
https://blog.dreamfactory.com/dreamfactory-2-10-release/
https://blog.dreamfactory.com/dreamfactory-2-11-release/
https://blog.dreamfactory.com/dreamfactory-2-12-release/