sap-cf-destination

convenience utility for calling a URL via a SAP CF destination

Usage no npm install needed!

<script type="module">
  import sapCfDestination from 'https://cdn.skypack.dev/sap-cf-destination';
</script>

README

SAP CP Cloud Foundry destination handler

Build Status npm Package

Install

npm install --save sap-cf-destination

Prerequisites

  • destination and destination instance created
  • connectivity instance created
  • xsuaa instance created
  • all of the above instances bound to the node app, e.g. via manifest.yml:
    applications:
    - name: my_app
      path: my_app
      memory: 128M
      services:
        - xsuaa-instance
        - connectivity-instance
        - destination-instance
    

Usage

const callDestination = require('sap-cf-destination');

// Promise chain
callDestination({
        url: '/api/json',
        connectivity_instance: 'connectivity-lite',
        uaa_instance: 'uaa-lite',
        destination_instance: 'destination-lite',
        destination_name: 'tbaas',
        http_verb: 'POST',
        payload: {
            "me": "here"
        }
    })
        .then(response => {
            // do sth clever from the response
            // of $server_behind_destination_'tbaas'/api/json
        })
        .catch(err => {
            // oh no 💩
        })
        
// async/await? 👏
// add the 'async' keyword to an outer function wrapping 'callDestination'
async function getIt() {
    try {
        const response = await callDestination({...});
        // do sth clever w/ the response
    } catch (err) {
        // oh no 💩
    }
}

API

sap-cf-destination(options) ⇒ Promise.<(any|never)>

Param Type Description
options Map configuration options for several CF service instances
options.url string the url to call in the destination, absolute path (including leading slash) e.g. /api/v1/json
options.connectivity_instance string name of the instance of the connectivity service
options.uaa_instance string name of the instance of the uaa service
options.destination_instance string name of the instance of the destination service
options.destination_name string name of the destination to use
options.http_verb 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' HTTP method to use
[options.payload] object payload for POST, PUT or PATCH
[options.formData] object mimic a browser for POSTing a form to the destination; implies http verb POST
[options.content_type] string value for "Content-Type" http header, e.g. "application/json"
[options.full_response] boolean whether to have the full response (including all headers etc) pass through to the caller (BE -> proxy -> client)
[options.tech_error_only] boolean get a rejection only if the request failed for technical reasons, so e.g. 404 is considered a valid response
[options.binary] boolean whether to expect (and deliver) a binary at @param url
[options.scc_name] string Location ID of the SAP Cloud Connector

Hints & Limitations

  • all major HTTP verbs are supported (GET, POST, PUT,PATCH,HEAD, DELETE,OPTIONS) per se
    BUT: if the proxy software decides to not let any of them pass through, the request originating from this module will of course fail
  • POST, PUT and PATCH only support a JSON payload. The payload itself can be a plain, deeply nested object; it will be stringified automatically
  • POST now supports both a JSON payload and a form-style ("like a browser") submission:
    callDestination({
      url: ...,
      http_verb: 'POST',
      formData: {
        field1: "some value",
        field2: JSON.stringify([ { "el1": "v1", "el2": "v2" } ])  // stringify deep nested objects and array structures
      }
    })
    
  • use scc_name: '<locID>' as a parameter to specify location ID of the SAP Cloud Connector (default: none)
    callDestination({
            //...
            scc_name: '<locID of SCC>'
        }).then(...).catch(...);
    
  • use full_response: true as a parameter to obtain the full response payload, e.g. to get access to response headers
    callDestination({
            //...
            full_response: true
        }).then(...).catch(...);
    
  • use tech_error_only: true as a parameter to only get a rejection if the request failed for technial reasons ("as long as it has a status code, it's a valid response")
    callDestination({
            //...
            tech_error_only: true
        }).then( response => {
            // even ☕️ ends up here
            // add
            //    full_response: true (see above)
            // to get response.statusCode
        }).catch( err => {
            // network layer problem or such
        });
    
  • do a download of a binary file by specifying the matching Content-Type of the file and setting binary to true;
    this will deliver a Buffer useable in writeStreams
    callDestination({
            //...
            content_type: 'application/zip',
            binary: true
        }).then( buffer => {
            // write Buffer
            fs.createWriteStream('file.zip')
              .write(buffer, 'binary')
              .end();
            // don't forget to listen to the error and finish event
            // ...
        }).catch(...);
    

License

Apache License 2.0

References