@snowdog/wombat

File based, headless CMS for building configurable APIs

Usage no npm install needed!

<script type="module">
  import snowdogWombat from 'https://cdn.skypack.dev/@snowdog/wombat';
</script>

README

Wombat

Simple open-source flat-file serverless Content Management Framework (headless-CMS) to build powerful API effortlessly.

Features

  • Simple - Designed to replace Wordpress in building simple company / product / event pages
  • Fast and lightweight - Serverless oriented, no framework, no database or other system-wide requirements
  • Two types of data - Unlike Contentful or Strapi, offers not only items collection, but also single entities, that can be used to build pages or store configuration
  • Full internationalization - Every piece content is assigned to one language, so you have complete freedom in customizing it
  • No strict schema - Do you need each item within a content type to do be different and have a different structure for each language? No problem, sky is the limit!
  • No Admin Panel - You are not limited by the UI or poor UX, just you and bunch of JSON and Markdown files
  • Front-end agnostic - Simple REST API can be used by any application

Setup

  1. Add Wombat as dependecy yarn add @snowdog/wombat
  2. Create content following Content structure description.
  3. Create wombat.config.json file. Can be just {} if you are okay with default setting.
  4. Add "dev": "wombat dev" to package.json scripts section
  5. Run yarn dev and enjoy working with your new API

Serverless deployment

This guide is for ZEIT Now, but setting up any other serverless env looks simillar.

  1. In package.json add automatic DB building after installing dependecies
     "scripts": {
       "now-build": "wombat build",
       "dev": "wombat dev"
     }
    
  2. Define new builds and routes in now.json acording to the example
  3. Copy collection.js and entity.js from examples
  4. Deploy your app via now

Config options

{
  "defaultLang": "en", // Fallback language when request is send without `lang` query param.
  "allowedOrigins": [], // List of domains used to set Access-Control-Allow-Origin (CORS) response header
  "wombatUrl": "http://api.your.app", // String to replace all occurences of {{wombatUrl}} with given URL.
  "dev": {
    "port": "3000", // Port used by the dev web server to listen for requests
    "build": true // Determines if new "database" file should be build from files before dev server will be started.
  }
}

Content structure

All content is kept in /content directory. Inside you need to define supported languages. For example, we want to have content just in English, so it will be /content/en.

Wombat supports two data types:

Collections

Designed to store sets of similar data, like blog posts, authors, job offers etc.

  • Collections are stored in collection directory inside each language.
  • Each collection and item of collection needs to be added as a directory.
  • Every property of an item collection needs to be a separate JSON or Markdown file.

Entities

Created to keep a single object like a landing page content or global configuration.

  • Entities are stored in entity directory inside each language.
  • Each entity needs to be added as a directory.
  • Every property of entity needs to be a separate JSON or Markdown file.
  • You can define the relation between entity and collection.

The Query object

The core of Wombat. It's the key to get data from collection and to supply entities with colection data.

{
  "query": {
    "name": "collectionName", // (required) collection name
    "sortBy": "title", // prop name used for sorting
    "sort": "desc", // `asc` (default), `desc` or `shuffle` - `sortBy` required to use it
    "shuffle": true, // Shuffle returned items
    "limit": 2, // limit numer of returned items
    "page": 1, // page number
    "perPage": 100, // numer of items per page
    "items": ["award", "about", "partner"], // Array of collection items IDs. Items order is preserved.
    "props": ["id", "content"] // return only selected object props
    "filter": {
      "prop": "published", // name of collection item property used to filtering
      "type": "date", // `value`, `number` or `date - type of the filtering
      "value": "2019-01-01", // value used for filtering, can be also array
      "from": "2019-01-01", // range start for `number` or `date` type
      "to": "2019-03-01" // range end for `number` or `date` type
    }
  }
}

Example content tree

content
└── en
    ├── collection
    |   └── blog
    |       └── why-wombat-poop-is-cube
    |       |   ├── content.md
    |       |   ├── featured-image.json
    |       |   └── title.json
    |       └── things-you-dont-know-about-wombats
    |           ├── content.md
    |           ├── featured-image.json
    |           ├── form-config.json
    |           └── title.json
    └── entity
        └── home
            ├── blog-posts.json
            ├── about.md
            └── hero-banner.json

API

/entity

Retrieve an entity item.

Example: To get home entity send request to /entity?name=home.

URL params:

  • name - (required) Name of entity
  • lang - Return content in given lang.

/collection

Retrieve the whole collection as array.

Examples:

Whole collection

/collection?name=blog

Whole collection, but only title and content

/collection?name=blog&props=title,content

Only items selected by ID

/collection?name=blog&items=why-wombat-poop-is-cube,things-you-dont-know-about-wombats

Two items from collection sorted by title descending

/collection?name=blog&limit=2&sortBy=title&sort=desc

Items from second page, up to five per page

/collection?name=blog&page=2&perPage=5

URL params:

  • name - (required) Name of collection.
  • lang - Return content in given lang.
  • sortBy - Prop name used for sorting.
  • sort - asc (default) or desc- sortBy required to use it.
  • shuffle - Shuffle returned items.
  • limit - Limit numer of returned items.
  • page - Page number.
  • perPage - Numer of items per page.
  • items - Comma separated list of collection items IDs. Items order is preserved.
  • props - Comma separated list of selected object props, GraphQL-like.
  • filter - Filtering config in form of stringified JSON object