Skip to content

Latest commit

 

History

History
560 lines (426 loc) · 11.5 KB

readme.md

File metadata and controls

560 lines (426 loc) · 11.5 KB

ttt-rest-service

JS Library which gives functionallity to create services for client-server communication with REST style

Library provides:

- default Service
- Composite classes:
    - Fetcher
    - ResponseProcessor
    - MimeParser
- Factories:
    - FetcherFactory
    - ServiceFactory

Use composite classes to create your own service if default Service does not fulfill the needs





Installation

npm i --save ttt-rest-service





Getting Started

import {
  Fetcher,
  MimeParser,
  ResponseProcessor,
  Service,
  FetcherFactory,
  ServiceFactory
} from 'ttt-rest-service'

import {
  ValidationError,
  StatusError,
  MimeError
} from 'ttt-rest-service/dist/errors'

// then look at one of example below





Fetcher and API Modules Metadata

Fetcher binds to the API Module metadata
API Module metadata is array of object which describe endpoints
Describe send data of endpoints with JSON Schema

API Module structure:

const authApiModule = [
    {
        // endpoint1
    },
    {
        // endpoint2
    },
]

Endpoint structure:

- method[string]
    request method
- url[string]
    request url. There is posibility to insert ID into url,
    use ".../image/delete/{{id}}/"
    to get ".../image/delete/id_102/"
- secure[boolean]
    help variable
- roles[array]
    help variable
- handler[string]
    name of the class method that will be generated
- headers[object]
    request headers
- schema[object]
    JSON schema of the data send by the request

ApiModuleExample:

    const authApiModule = [
    {
      method: 'POST',
      url: '/auth/login',
      secure: false,
      handler: 'login',
      roles: [],
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        Credentials: 'include'
      },
      schema: {
        type: 'object',
        required: [ 'username', 'password' ],
        properties: {
          username: {
            type: 'string',
            minLength: 3
          },
          password: {
            type: 'string',
            minLength: 6
          }
        }
      },

    },
    {
      method: 'GET',
      url: '/auth/logout/{{id}}',
      secure: true,
      handler: 'logout',
      roles: [ 'user' ],
      headers: {
        Accept: 'application/json',
        Credentials: 'include'
      },
      schema: {
        // another JSON Schema
      },
    },
  ]





Example of usage



MimeParser && ResponseProcessor:

const { MimeParser, ResponseProcessor } = require("ttt-rest-service")

const mimeParserPairs = [
    [ 'application/json', ( httpResponse ) => httpResponse.json() ]
]
const mimeParser = new MimeParser( mimeParserPairs )
const responseProcessor = new ResponseProcessor( mimeParser )

async function example() {
    const request = await fetch( 'some-url.com/get-instance' )
    const processedResponse = await responseProcessor.processResponse( request )
}

example()

Fetcher

const { FetcherFactory } = require('ttt-rest-service')

const authModule = [
  {
    method: 'POST',
    url: '/auth/login',
    secure: false,
    handler: 'login',
    roles: [],
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    schema: {
      type: 'object',
      required: [ 'username', 'password' ],
      properties: {
        username: {
          type: 'string',
          minLength: 3
        },
        password: {
          type: 'string',
          minLength: 6
        }
      },
    },
  },
];

const fetcherFactory = new FetcherFactory()
const fetcher = fetcherFactory.getFetcher(authModule)
const authToken = localStorage.get('authToken')

fetcher.onBeforeRequest(( requestParameters ) => {
    if(requestParameters.secure && authToken === null) {
        return true // prevent fetch
    } else {
        requestParameters.fetchParams.headers.Authorization = `Token ${ authToken }`
    }
})

async function example() {
    const sendData = {
        username: 'username',
        password: 'strong_password'
    }
    const request = await fetcher.request({ handlerName: 'login', data: sendData })
}

example()

Service

const { Service, fetcherFactory, mimeParser, responseProcessor } = require('ttt-rest-service')

const authModule = [
  {
    method: 'POST',
    url: '/auth/login',
    secure: false,
    handler: 'login',
    roles: [],
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    schema: {
      type: 'object',
      required: [ 'username', 'password' ],
      properties: {
        username: {
          type: 'string',
          minLength: 3
        },
        password: {
          type: 'string',
          minLength: 6
        }
      },
    },
  },
];

const fetcherFactory = new FetcherFactory();
const fetcher = fetcherFactory.getFetcher( authModule );

const mimeParserPairs = [
    [ 'application/json', ( httpResponse ) => httpResponse.json() ]
];
const mimeParser = new MimeParser( mimeParserPairs );
const responseProcessor = new ResponseProcessor( mimeParser );

const service = new Service(fetcher, responseProcessor)

service.onBeforeRequest(({ handlerName, data, id}) => {
    data.processedInBeforeRequest = true
    return {
        handlerName,
        data,
        id
    }
})

service.onResponseHandled(({ handledResponse }) => {
    handledResponse.parsedBody.processedInHook = true
})

async function exampleWithRequest() {
    const request = await service.request({
        handlerName: 'login',
        data: {
            username: 'username1',
            password: 'very_very_strong'
        }
    })
}

async function exampleWithSpecifiedHandler() {
    service.addHandler('login', authModule.schema)
    service.login({
        username: 'username1',
        password: 'very_weak_password'
    })
}

ServiceFactory

const { ServiceFactory, FetcherFactory, MimeParser, ResponseProcessor } = require('ttt-rest-service')

const API = {
    auth: [
        {
            method: 'POST',
            url: 'url.com/login/',
            secure: false,
            handlerName: 'login',
            roles: [],
            headers: {
                'Content-Type': 'application/json',
                Accept: 'application/json'
            },
            schema: {
                //...
            }
        }
    ],
    user: [
        {
            method: 'GET',
            url: 'url.com/user/{{id}}',
            secure: true,
            handlerName: 'getUser',
            roles: [],
            headers: {
                Accept: 'application/json'
            },
            schema: {
                // ...
            }
        }
    ]
}

const fetcherFactory = new FetcherFactory();

const mimeParserPairs = [
    [ 'application/json', ( httpResponse ) => httpResponse.json() ]
];
const mimeParser = new MimeParser( mimeParserPairs );
const responseProcessor = new ResponseProcessor( mimeParser );

const serviceFactory = new ServiceFactory( fetcherFactory, responseProcessor );
const services = serviceFactory.generateServices( API )

const authService = services.authService
const userService = services.userService

authService.login({
    username: 'username1',
    password: 'password1'
})

const userId = 'user_id_12343'
userService.getUser({
    allInformation: true
}, userId)





Library API

FetcherFactory


getFetcher( apiModuleSchema )

apiModuleStructure:

const anApiModule = [
  {
    method: 'POST',
    url: 'url.com/login/',
    secure: false,
    handlerName: 'login',
    roles: [],
    headers: {
     // ...
    },
    schema: {
      //...
    }
  },
  {
    // endpoint 2
    // ...
  }
]

Schema in endpoint metadata MUST BE IN JSON SCHEMA FORMAT




Fetcher


onBeforeFetch( callback )

Arg Type Default Description
callback function () => false The function which will be called as a hook

If you want prevent fetch execution, then your callback should return true



request( { handlerName, data = {}, id } )

Arg Type Default Description
handlerName string undefined request name
data object {} request payload
id string undefined url id

If there is no {{id}} template in metadata url, id will not be inserted




ResponseProcessor


constructor( mimeParser, invalidStatuses )

Arg Type Default Description
mimeParser MimeParser undefined Helper class for parsing response body
invalidStatuses array [] Array of statuses that will be considered invalid



processResponse( httpResponse )

Arg Type Default Description
httpResponse Response undefined Response that will be processed

If response contains body functino returns,

{
    parsedBody,
    httpResponse,
}

else returns passed httpResponse




MimeParser


constructor( mimeParserPairs )

Arg Type Default Description
mimeParserPairs array [] Pairs of mime-type and parser-function in mapable1 format




Service


constructor(fetcher, responseProcessor, name)

Arg Type Default Description
fetcher Fetcher null Instance of Fetcher
responseProcessor ResponseProcessor null Instance of ResponseProcessor
name string undefined Service name



request({ handlerName, data, id })

Arg Type Default Description
handlerName string undefined Name of endpoint specified in endpoint metadata by handler property
data object {} Request send data
id string undefined A string which will replace {{id}} template in url



addHandler( handlerName, dataSchema )

Arg Type Default Description
handlerName string undefined The name of property which will be set on a service instance
dataSchema object undefined The data schema of request send data



onBeforeRequest( callback )

Arg Type Default Description
callback function (val) => val The function which will be called as a hook



onResponseHandled( callback )

Arg Type Default Description
callback function (val) => val The function which will be called as a hook



onBeforeFetch( callback )

Arg Type Default Description
callback function (val) => val The function which will be called as a hook




ServiceFactory


generateServices( api )

Arg Type Default Description
api object undefined An object that describe API modules;



generateService( apiModuleName, apiModuleSchema )

Arg Type Default Description
apiModuleName string undefined Name of module which will be set as name of a service
apiModuleSchema object undefined The metadata of endpoint




Footnotes

  1. mapable means array which can be used for creating of map