npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

api-mount-server

v1.0.13

Published

Library for making communication between front-end and back-end simple

Downloads

24

Readme

api-mount-server

by Vytenis Urbonavičius

api-mount-server library provides a straightforward way of exposing API from a Node.js server application for consumption on a client side using api-mount-client library.


Installation

Consider using a more universal library - api-mount. api-mount contains both server and client code in one package. Usage and available methods are identical to api-mount-server. Only package name differs.

If you want to continue using a server-only version:

npm install --save api-mount-server

Usage

Constructing API objects


This library allows exposing API objects. These objects can be constructed in multiple ways.

Simple object with methods:

const api = {
  foo() {
    return 'foo'
  },
}

Set of functions collected into an API object:

// api.js
export const foo = () => 'foo'
// mount.js
import * as api from './api'
// ...

Object created from a class

class SomeClass {
  foo() {
    return 'foo'
  }
}

const api = new SomeClass()

Static class (if supported)

class StaticClass {
  static foo() {
    return 'foo'
  }
}

There may be more ways but these are just a few examples to showcase the possibilities.

Writing API methods


API methods are normal methods or functions with one constraint - they can only operate with serializable values (arguments, return value). In this case serializable value is a value which can be converted into JSON using JSON.stringify() method.

In addition to the rule above, API may be asynchronous - it may return a Promise if needed. It can also throw an exception.

Asynchronous API function example:

// Using timer to simulate asynchronous behavior
const foo = () => new Promise(resolve => setTimeout(() => resolve('foo'), 1000))

Synchronous API function example:

const foo = () => 'foo'

Please note that even when synchronous API is used, client will see these return values as promises which can be extracted either with .then or with async keyword:

// ...

console.log(await API.foo()) // 'foo'

// or

API.foo().then(console.log) // 'foo'

// ...

You can find more information about how API can be accessed from client side here: api-mount-client

Exposing API object


import {apiMountFactory} from 'api-mount-server'

const api = {
  /* ... API methods ... */
}

const ApiMount = apiMountFactory()
ApiMount.exposeApi(api)

When exposing non-class-based objects, one needs to be aware that API will not be namespaced by default. In other words, foo will be accessible via HTTP directly as:

  /foo

This may cause trouble when exposing multiple APIs - name clashes can cause trouble, also api methods from several API objects may be fused together into a single API object from the perspective of a client.

One possible solution is to provide namespaces manually like this:

ApiMount.exposeApi(api, {basePath: '/some-namespace'})

There is also an easier way for those who prefer using classes. Namespaces are added automatically when using exposeClassBasedApi:

class SomeClass {
  foo() {
    return 'foo'
  }
}

ApiMount.exposeClassBasedApi(new SomeClass())

In this case foo will become available via HTTP as:

/some-class/foo

If one uses configuration which supports static classes (i.e. TypeScript), following approach can be used:

class StaticClass {
  static foo() {
    return 'foo'
  }
}

ApiMount.exposeClassBasedApi(StaticClass)

In this case foo will become accessible via HTTP as:

/static-class/foo

CORS


One common problem when starting to use api-mount-server is that requests are blocked by browser's CORS policy. Depending on client configuration symptoms may be either completely blocked requests or opaque responses (i.e. missing response information).

There are multiple ways to solve this problem like serving from same domain as client, using proxies, etc. However, one of the quickest solutions/workarounds is using cors npm package when serving API to state that cross-domain requests should be accepted:

// ...
const ApiMount = apiMountFactory({
  beforeListen: app => {
    // This is just for testing purposes
    // You would probably want to explicitly list
    // where you expect requests to be coming from
    // for security reasons
    app.use(require('cors')())
  },
})
// ...

Supported Configuration

As one could see in the above examples, it is possible to pass configuration object which alters behavior of api-mount. All these methods accept configuration object as (last) argument:

  • apiMountFactory
  • exposeClassBasedApi
  • exposeApi

Configuration object may contain following keys:

  • name - express app name - only needed in corner case when there are several express apps initialized manually at the same time (using injectLaunchCode).
  • basePath - path to be added to HTTP address before automatically generated part. Mostly useful for name-spacing.
  • beforeListen - hook for altering Express configuration. It is very useful for things like CORS configuration, etc. This hook will not fire nor it is needed if custom launch code is injected.
  • beforeExecution - hook for injecting logic before handling api request.
  • beforeResponse - hook for customizing server response logic.
  • afterResponse - hook for injecting logic after server responds.
  • port - server port number - only available when calling apiMountFactory.

Should one want to customize how express app is initialized, this is how it can be done:

injectLaunchCode(() => {
  const newApp = express()
  newApp.use(bodyParser.urlencoded({extended: false}))
  newApp.use(bodyParser.json())
  newApp.listen(3007)
  return newApp
})

Above example would override default express app initialization. However, should one want to have several different ways to initialize it, injectLaunchCode supports a second argument - name. It must match name which is provided in configuration object when exposing api or using apiMountFactory.

More information can be found in docs directory inside the api-mount-server package. Also, code suggestions should be available provided a compatible IDE is used (such as VSCode).

Protocol

api-mount-server is designed to expose API from a Node.js server. However, one might want to expose API from a different kind of back-end and still be able to consume it via api-mount-client. In order to do that one has to follow rules explained below. Note that although rules are customizable, below explanation describes default behavior.

Each API method name should be changed to param-case and exposed as HTTP path.

In case of successful response, HTTP status should be 200.

In case of error response (promise rejection or exception), HTTP status should be 500.

All requests should be of method POST.

All arguments for API methods should be provided via body JSON which looks like this:

{
  "args": []
}

Argument values should be listed under args in a JSON format.

Response should be returned as a JSON object which either carries method return value or error information. As long as response is a valid JSON, there are no other defined constraints.

TypeScript

When consuming some API exposed by api-mount-server, it would be convenient to have code suggestions (typings) available. This functionality is currently out of scope for api-mount but can be achieved with a reasonably minor effort.

If one is developing using TypeScript, it allows generating .d.ts files.

Let's say our API is a class defined inside api.ts file. TSC can generate a corresponding api.d.ts file for it. This file could then be shared with client in some way. For example - one could publish a package containing these generated typings every time server gets published.

When client creates an api object using api-mount-client, this object/class could then be matched with a generated d.ts.