funkster-http-json

Funkster is a compositional server library. This package provides types and combinators to parse json bodies from requests and respond with json to the client.


Keywords
server, node, funkster, http, web, json, body
License
Unlicense
Install
npm install funkster-http-json@0.7.16

Documentation

funkster-http-json

npm node npm Travis

Icon

Funkster is a compositional server library. This package provides types and combinators to parse json bodies from requests and respond with json to the client.

Typscript is used to illustrate the examples.

Install

$ npm install funkster-http-json

Build

$ npm install && npm run build

Test

$ npm run test

Parsing JSON from a request body

The parseJson and parseJsonWith combinators can be used to parse JSON data from a request. In a valid request the Content-Type header contains json and a request body must be present, otherwise a 415 Unsupported Media Type is returned.

Example:

import * as http from 'http';
import { parseJson } from 'funkster-http-json';
import { asRequestListener, Ok } from 'funkster-http';

interface User {
  name: string;
}

const greet = parseJson<User>(user => Ok('Hello ' + user.name));
const server = http.createServer(asRequestListener(greet));

// start the node HTTP server and send e.g. a POST with '{ "name": "John Connor" }'.

It is possible to use a custom JSON deserializer. The default is JSON.parse.

Custom deserializer:

import * as http from 'http';
import { parseJsonWith } from 'funkster-http-json';
import { asRequestListener, Ok } from 'funkster-http';

interface User {
  name: string;
}

function deserializeJson<User>(json: string): User {
  return /* your custom json deserialization here */
}

const greet = parseJsonWith<User>(user => Ok('Hello ' + user.name), deserializeJson);
const server = http.createServer(asRequestListener(greet));

// start the node HTTP server and send e.g. a POST with '{ "name": "John Connor" }'.

Sending JSON to the client

The sendJson and sendJsonWith combinators can be used to send proper JSON responses to the client. In a valid request the Accept header allows json, otherwise a 406 Not Acceptable is returned.

Example:

import * as http from 'http';
import { sendJson } from 'funkster-http-json';
import { asRequestListener } from 'funkster-http';

const greet = sendJson({ hello: "John Connor" });
const server = http.createServer(asRequestListener(greet));

// start the node HTTP server and send a simple GET.

The Content-Type of the response will be set to application/json; charset=utf-8.

It is possible to specify a custom response handler (default: 200 OK) and JSON serializer (default: JSON.stringify).

Custom response handler and serializer:

import * as http from 'http';
import { compose } from "funkster-core";
import { sendJsonWith } from 'funkster-http-json';
import { setContentType } from "funkster-http-headers-content";
import { Accepted, asRequestListener, HttpPipe } from 'funkster-http';

function respondWithJson(json: string): HttpPipe {
  return compose(
    setContentType({ type: "application/json", parameters: { charset: "ascii" } }),
    Accepted(json));
}

function serialize(obj: any): string {
  return /* your custom json serialization here */
}

const greet = sendJsonWith({ hello: "John Connor" }, respondWithJson, serialize);
const server = http.createServer(asRequestListener(greet));

// start the node HTTP server and send a simple GET.

Building a JSON api

The mapJson and mapJsonWith combinators allow to build a HttpPipe that consumes JSON requests, maps the data and produces JSON responses.

Example:

import * as http from 'http';
import { mapJson } from 'funkster-http-json';
import { asRequestListener } from 'funkster-http';

interface User {
  id: string;
}

interface UserInfo {
  name: string;
  age: number;
  city: string;
}

function lookup(user: User): Promise<UserInfo> {
  if(user.id !== 1234) {
    return Promise.resolve(null);
  }

  return Promise.resolve({
    name: 'John Connor',
    age: 42,
    city: 'Los Angeles'
  });
}

const getUserInfo = mapJson<User, UserInfo>(lookup);
const server = http.createServer(asRequestListener(getUserInfo));

// start the node HTTP server and send e.g. a POST with '{ "id": "1234" }'.

Internally mapJson uses parseJson and sendJson so the same rules apply. It is possible to specify the parse and send functions via mapJsonWith.

Custom response handling:

import * as http from 'http';
import { mapJson, parseJson, sendJson } from 'funkster-http-json';
import { asRequestListener, NotFound } from 'funkster-http';

interface User {
  id: string;
}

interface UserInfo {
  name: string;
  age: number;
  city: string;
}

function lookup(user: User): Promise<UserInfo> {
  if(user.id !== 1234) {
    return Promise.resolve(null);
  }

  return Promise.resolve({
    name: 'John Connor',
    age: 42,
    city: 'Los Angeles'
  });
}

function sendUserInfo(userInfo?: UserInfo): HttpPipe {
  if(!userInfo) {
    return NotFound();
  }

  return sendJson(userInfo);
} 

const getUserInfo = mapJsonWith<User, UserInfo>(lookup, parseJson, sendUserInfo);
const server = http.createServer(asRequestListener(getUserInfo));

// start the node HTTP server and send e.g. a POST with '{ "id": "1234" }'.

Meta

Icon funky by iconsmind.com from the Noun Project.