JSPM

@beardedtim/cms-server

0.0.2
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • 0
    • Score
      100M100P100Q28206F
    • License UNLICENSE

    An abstraction for creating RESTful MongoDB microservices

    Package Exports

    • @beardedtim/cms-server

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@beardedtim/cms-server) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    @beardedtim/cms-server

    WIP

    Build Status

    codecov

    Overview

    This is very much a WIP. It currently is aiming to do two things:

    1. Simplify the startup of a Koa project
    2. Encourage building instead of setting up

    I am hoping eventually to have this as a working Blogging/page-building platform. As of now, it is easy to add basic endpoints such as /resource and /resource/:id with little configuration.

    Currently, the server only supports Node v7.9.0. Checkout nvm for managing node versions

    Configuration API

    {
        collections: [
          {
            resource: 'collectionName',
            pre: [ ... ], // async functions to run BEFORE route
            post: [ ... ], // async functions to run AFTER route
            protected: true, // if this is a protected route
            authFn: validateFunc // custom async validation
            route: KoaRoute // a KoaRouter compatable obj | defaults to Base(config) | no route pre/post added
          }
        ],
        pre: [ ... ], // async functions to run BEFORE ALL routes
        post: [ ... ], // async functions to run AFTER ALL routes,
    }

    Developing

    $ git clone https://github.com/beardedtim/cms-server.git
    
    $ cd cms-server
    
    $ cp .env.example .env
    
    $ yarn
    
    $ yarn dev

    You will need a mongodb instance running and have the correct MONGO_URI set in your .env file.

    Working Examples:

    Below you will find 4 examples of how to use the API. To run examples:

    $ git clone https://github.com/beardedtim/cms-server.git
    
    $ cd cms-server
    
    $ yarn
    
    $ cd examples
    
    $ cd defaults
    
    $ cp .env.example .env
    
    $ node server.js

    Data Flow

    Each request to a valid endpoint will flow:

    1. Set expected values for
    2. All config.pre functions are applied in order
    3. All collections are added as routes in order
    4. All config.post functions are applied in order

    Tutorial:

    Working Example v.0.0.1

    Inside of our root directory:

    $ yarn add @beardedtim/cms
    
    $ touch index.js
    
    $ touch .env

    Add the following to .env:

    PORT=5001
    MONGO_URI=mongodb://localhost:32770/explore
    AUTH_NAME=timi
    AUTH_PASS=1234

    Fill in the correct MONGO_URI that you are using. If you are not already, checkout Docker and Kitematic for an almost point and click setup experience.

    Then inside of index.js:

    const dotenv = require('dotenv');
    const Koa = require('koa');
    
    dotenv.config();
    
    const app = new Koa();
    const cmsServer = require('./').server;
    
    cmsServer.booststrap(app);
    
    app.listen(5000);

    We now have a functional applicaton at http://localhost:5001 with an endpoint at /documents and /documents/:id. It also has protected routes for PUT,PATCH,DELTE methods.

    Go ahead and try a GET requests to http://localhost:5001/documents. It should return the following:

    {
        data: []
    }

    Which means we have no documents. Let's fix that. Add the following to your request header and make a POST request:

    Authorization: Basic dGltaToxMjM0
    Content-Type: application/json
    Body: {
        name: 'Tim'
    }

    This can be done inside of postman by clicking Authorization, choosing Basic and typing timi for the name and 1234 for the password. It can also be added via fetch:

    fetch('http://localhost:5001/documents', {
        method: 'POST',
        headers: {
            'Authorization': 'Basic dGltaToxMjM0',
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            name: 'Tim'
        })
    })

    NOTE: If you get TypeError: Cannot create property '_id' on string, it is probably because you did not set Content-Type to application/json

    You should get back the following:

    {
      "data": {
        "insertedIds": [
          "58fd730a37b1e45c818003b2"
        ]
      }
    }

    If you get:

    {
      "error": {
        "code": 406,
        "message": "Unacceptable content-type! It must be applcation/json"
      }
    }

    This is because you did not set the Content-Type header correctly.

    Now let's go back to GET /documents and see what we get:

    {
        data: [
            // ... whatever you pushed
        ]
    }

    And we should have an _id. Go ahead and copy that and go to:

    http://localhost:5001/documents/<ID HERE>

    It should return:

    {
      "data": {
        "_id": "58fd26666464e505d044556d",
        "name": "Tim"
      }
    }

    Or whatever you set that record to.

    This is a boring record so let's delete it:

    DELETE /documents/:id

    DELETE /documents/58fd26666464e505d044556d

    should return something like:

    {
      "data": {
        "n": 1,
        "ok": 1
      }
    }

    And if we want to delete the whole collection of documents and start again?

    DELETE /documents

    should return:

    {
      "data": true
    }

    And when we GET /documents, we should be met with:

    {
        data: []
    }

    Adding Custom Functionality

    Adding Custom 404

    boostrapConfig = {
        // ...
        post: [
            async (ctx, next) => {
                if (!ctx.body) {
                    ctx.body = {
                        error: {
                            droids: 'not the ones you are looking for',
                        }
                    }
                }
            }
        ],
    }

    request: GET /not/real/route

    response:

    {
      error: {
        droids: 'not the ones you are looking for'
      }
    }

    Adding Custom Query Validation

    boostrapConfig = {
        // ...
        pre: [
            async (ctx, next) => {
                const { query } = ctx.request;
                const isValid = customValidation(query);
                if (!isValid) {
                    ctx.errors.custom({
                        code: 406,
                        message: 'Not valid query!',
                    });
                }
            }
        ]
    }

    request: GET /documents?invalid=true

    response:

    {
      error: {
        code: 406,
        message: 'Not valid query!',
      }
    }