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

@beardedtim/cms

v0.0.1

Published

A basic CMS with Redis for index/searching

Downloads

5

Readme

@beardedtim/cms

WIP

Build Status

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.

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 [email protected]:beardedtim/cms.git

$ cd cms

$ cp .env.example

$ 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 [email protected]:beardedtim/cms.git

$ cd cms

$ yarn

$ cd examples

$ cd defaults

$ cp .env.example

$ 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:

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!',
  }
}