0.0.2 • Published 2 years ago

@fastifysc/create-fastify v0.0.2

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

Sample Crud

'use strict'

const got = require('got')

const svc = (port) => `http://localhost:${port}`;

const get = async (uri) => await got(uri, { timeout: 500, retry: 0 }).json();

const { APORT, BPORT } = process.env;

const alpha = svc(APORT);

const beta = svc(BPORT);

const schemas = {
  post: {
    type: 'object',
    required: ['data'],
    additionalProperties: false,
    properties: {
      data: {
        type: 'object',
        required: ['brand', 'color'],
        additionalProperties: false,
        properties: {
          brand: { type: 'string' },
          color: { type: 'string' },
        }
      }
    }
  }
  , validResponse: {
    params: {
      id: {
        type: 'integer'
      }
    }
    , response: {
      200: {
        type: 'object',
        required: ['hello']
        , properties: {
          hello: { type: 'string' }
        }
      }
    }
  }
};

module.exports = async (fastify, opts) => {

  const { notFound } = fastify.httpErrors

  const { uid, insert, select, update, remove } = fastify.store;

  fastify.get('/:id', async (request, reply) => {

    const { id } = request.params

    try {

      return await select(id)

    } catch (error) {

      if (error.message === 'not found') {
        throw notFound()
      }

      throw error

    }

  })

  fastify.post('/', { schema: { body: schemas.post } }, async (request, reply) => {

    const { data } = request.body

    const id = uid()

    await create(id, data)

    reply.code(201)

    return { id }

  })

  fastify.post('/:id/update', async (request, reply) => {

    const { id } = request.params

    const { data } = request.body

    try {

      await update(id, data)

      reply.code(204)

    } catch (error) {

      if (error.message === 'not found') {
        throw notFound()
      }

      throw error

    }

  })

  fastify.put('/:id', async (request, reply) => {

    const { id } = request.params
    const { data } = request.body

    try {

      await insert(id, data)

      reply.code(201)

      return {}

    } catch (error) {

      if (error.message === 'resource exists') {

        await update(id, data)

        reply.code(204)

      } else {

        throw error

      }

    }

  })

  fastify.delete('/:id', async (request, reply) => {

    const { id } = request.params

    try {

      await remove(id)

      reply.code(204)

    } catch (error) {

      if (error.message === 'not found') {
        throw notFound()
      }

      throw error

    }

  });

  fastify.get('/from', async function (request, reply) {

    const { url } = request.query;

    if (!url) {
      throw fastify.httpErrors.badRequest();
    }

    try {

      new URL(url);

      reply.from(url);

    } catch (err) {

      throw err;

    }

  });

  fastify.get('/combine/:id', async function (request, reply) {

    const alphaId = request.params.id;

    try {

      const { id, attr1, attr2 } = await get(`${alpha}/${alphaId}`);

      const { attr3 } = await get(`${beta}/${attr1}`);

      return { id, attr1, attr2, attr3: attr3 };

    } catch (error) {

      if (error.response && error.response.statusCode === 400) {
        throw httpErrors.badRequest();
      }

      if (error.response && error.response.statusCode === 404) {
        throw httpErrors.notFound();
      }

      throw error;

    }

  });

  fastify.get('/response/:id', { schema: schemas.validResponse }, (request, reply) => {

    reply.send({ hel1lo: 'world' })

  })

}

Sample Plugin

'use strict'

const fp = require('fastify-plugin')

const banned = ['BANNED_IP'];

module.exports = fp(async function (fastify, opts) {

  fastify.addHook('onRequest', function ({ ip }, reply, next) {

    if (!banned.includes(ip)) {
      return next();
    }

    reply.code(403).send();

  });

});

Sample Store

'use strict'

const fp = require('fastify-plugin');
const { promisify } = require('util')

const state = { 1: { att1: 'v1', att2: 'vv1' }, 2: { att1: 'v2', att2: 'vv2' } };

module.exports = fp(async function (fastify, opts) {

  fastify.decorate('store', {
    uid
    , insert: promisify(insert)
    , select: promisify(select)
    , update: promisify(update)
    , remove: promisify(remove)
  });

});

function insert(id, data, cb) {

  if (exists(id)) {
    return void resourceExists();
  }

  state[id] = data;
  setImmediate(() => cb(null, id));

}

function select(id, cb) {

  if (!exists(id)) {
    return void validateNotFound(cb);
  }

  setImmediate(() => cb(null, state[id]));

}

function update(id, data, cb) {

  if (!exists(id)) {
    return void validateNotFound(cb);
  }

  state[id] = data;
  setImmediate(() => cb());

}

function remove(id, cb) {

  if (!exists(id)) {
    return void validateNotFound(cb);
  }

  delete state[id]
  setImmediate(() => cb())

}

function exists(id) {
  return state.hasOwnProperty(id);
}

function resourceExists(cb) {
  setImmediate(() => cb(err('E_RESOURCE_EXISTS', 'resource exists')));
}

function validateNotFound(cb) {
  setImmediate(() => cb(err('E_NOT_FOUND', 'not found')));
}

function err(code, message) {
  const err = Error(message);
  err.code = code;
  return err;
}

function uid() {

  return Object.keys(state)
    .sort((a, b) => a - b)
    .map(Number)
    .filter(n => !isNaN(n))
    .pop()++;

}

Dependencies

    "fastify": "^3.0.0",
    "fastify-autoload": "^3.3.1",
    "fastify-cli": "^2.14.0",
    "fastify-http-proxy": "^6.2.1",
    "fastify-plugin": "^3.0.0",
    "fastify-reply-from": "^6.4.1",
    "fastify-sensible": "^3.1.0",
    "got": "^11.8.2"