Skip to Content
Technical Articles

Exposing SAP Business One Service Layer through Node JS

Introduction

I’ve been working with SAP Business One (as a developer) for a while and i can say that i am really excited with all the stuff related with the intelligent enterprise, loosely coupled solutions, sap business technology plattform and so on. At Expertone we are very committed with this kind of innovations and we’ve participated in two sap business one hackathons where we could learn a lot and having a lot of fun.

You have a lot of information about all the great posibilites at business one extensibility community managed by the super sap business one solution architects team

I’d like to write some blog posts about basic aspects for exposing Service Layer SAP Business One through node js web services. This is very useful for

  1. Loosely coupled solutions: having business logic on the cloud you can have some kind of multi tenant products connected to your customers via Service Layer. For extra security you can use sap cloud connector.
  2. Aggregation of different Service Layer endpoints in one node js service endpoint
  3. Integration with other REST services like xsjs/xsodata service, sap api hub services, ecommerce services
  4. Manage same origin policy (sop) of browsers through CORS nodejs module
  5. Other great posibilities…

Well, first things first. There are two posibilities:

  1. You don’t have a HANA Box with Service Layer
  2. You have a HANA Box with Service Layer

(Remember: You can use Service Layer with SQL Server SAP B1 version)

You don’t have a HANA Box with Service Layer

No problem, you can try Service Layer api using SAP API Business Hub. You can register at api hub and search for “SAP Business One”. You will find some endpoints for playing:

Once you register you will have an api key. With this key you can try the services.

For example:

I will try “Orders” api

If you navigate to “Details” you will find the api sandbox url:

You can search for any http method you want. I want to try GET method in Orders endpoint:

You can see a definition of the endpoint, which OData parameters you can use and so on…

Having our endpoint url and our api key we can try it via Postman:

As you can see, you need to select “GET” method, insert your url endpoint and your apiKey as a http header. Pressing “Send” button you will get a list of Orders in JSON format. Each “value” entry represents a B1 sales order:

This is enough for our purpose.

Let me start with node js stuff:

Node js stuff

Create my Project. The best option for me is creating a new repository at github.com and cloning it:

https://github.com/Naukite/b1slnode.git

Well, i have source code control and a repository for writing my node solution. This looks pretty Good.

I initialize my project with npm

Npm init –yes will create a basic package.json file with no asking anything. This is an empty node js project.

I will use express for exposing my services so let me add this dependency with npm

I use dotenv module for storing my setup information. With dotenv you can have a file where declarating your configuration info. This file is called “.env”:

I stored service layer url, my apiKey and my listening port.

For installing dotenv just execute:

This will add a development dependency (–save-dev modifier). I’ll show you this entry at package.json:

I will write my main file “server.js”:

const emoji = require('node-emoji')
if (process.env.NODE_ENV !== 'production') {
    require('dotenv').config()
}
const express = require("express")
const app = express()

app.get('/api/ping', (req, res) => {
    res.send(emoji.emojify("pong!!:8ball: :8ball: :8ball:"))
})

app.listen(process.env.PORT, () => {
    console.log(`SERVICELAYER: ${process.env.SERVICELAYER}`)
    console.log(emoji.emojify(`:rocket::rocket::rocket: --> Listening at port: ${process.env.PORT}...`))    
}) 

node-emoji will allow me to show some cool emojis via console.

I check my environment variables looking for “NODE_ENV” variable.

If NODE_ENV exists and its value is `production’ we will not use our .env file, else i will use my .env stored information. This is done importing dotenv module whith require and executing config function.

if (process.env.NODE_ENV !== 'production') {
    require('dotenv').config()
}

Secondly i require “express” module and get an app object via an express() function call.

After this i will define our first route /api/ping. app.get will respond any http GET request to first parameter route with a function as second parameter :

const express = require("express")
const app = express()

app.get('/api/ping', (req, res) => {
    res.send(emoji.emojify("pong!!:8ball: :8ball: :8ball:"))
})

If you send a GET request to /api/ping you will get ‘pong’ with eight ball three times.

Lastly i launch our listening process:

app.listen(process.env.PORT, () => {
    console.log(`SERVICELAYER: ${process.env.SERVICELAYER}`)
    console.log(emoji.emojify(`:rocket::rocket::rocket: --> Listening at port: ${process.env.PORT}...`))    
}) 

Well, let’s check what i’ve done:

Executing node application with “node server.js”:

 

 

Sending a GET request to /api/ping route with curl:

Well, it works. It’s time to ask Order documents to SAP B1 through our services:

 

Interacting with Service Layer from Node js

I will use fetch for making requests to remote endpoints. As usual you can install it using “npm i node-fetch”. You can write a proxy class like this:

const fetch = require('node-fetch');
let proxy = null

function Proxy(slUrl, apiKey) {
    this.slUrl = `${slUrl}/b1s/v2/`
    this.apiKey = apiKey
    this.request = {
        headers: {
            apiKey: this.apiKey
        } 
    }

    this.get = async (endpoint) => {
        return fetch(`${this.slUrl}${endpoint}`, this.request).then(r => r.json())
    }

    return this
}

function GetProxy() {
    if (!proxy) 
        proxy = new Proxy(process.env.SERVICELAYER, process.env.APIKEY)
    return proxy
}

module.exports = GetProxy

I’ve implemented a singleton pattern for getting a proxy object exposing GetProxy function.

If you instance a Proxy object you will be able to invoke get method with a Service Layer endpoint and you will get what you need.

I register a route using:

const ordersRouter = require('./routes/Orders')

app.use('/api/orders', ordersRouter)

This works like my ping endpoint but i need to write routes/Orders.js for taking care of /api/orders requests:

const express = require('express')
const router = express.Router()
const proxy = require('../lib/Proxy')()

router.get('/', async (req, res) => {
    res.send(await proxy.get("Orders"))
    
})

module.exports = router

Ww got it, if i send a get request to http://localhost:8080/api/orders i will receive orders from api hub Orders endpoint.

 

What’s next?

This was enough for testing purposes but we will need authentication, authorization and a lot of stuff not covered here. I will write other post supposing we have a HANA box and we log in via Service Layer and how we can manage our users sessions.

Thanks for reading!

Nau

2 Comments
You must be Logged on to comment or reply to a post.