1 | <p align="center">
|
2 | <img src="./assets/logo.svg" height="200">
|
3 | </p>
|
4 |
|
5 | # Wombat
|
6 | Simple open-source flat-file serverless Content Management Framework (headless-CMS) to build powerful API effortlessly.
|
7 |
|
8 | ## Features
|
9 | - **Simple** - Designed to replace Wordpress in building simple company / product / event pages
|
10 | - **Fast and lightweight** - Serverless oriented, no framework, no database or other system-wide requirements
|
11 | - **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
|
12 | - **Full internationalization** - Every piece content is assigned to one language, so you have complete freedom in customizing it
|
13 | - **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!
|
14 | - **No Admin Panel** - You are not limited by the UI or poor UX, just you and bunch of JSON and Markdown files
|
15 | - **Front-end agnostic** - Simple REST API can be used by any application
|
16 |
|
17 |
|
18 | ## Setup
|
19 | 1. Add Wombat as dependecy `yarn add @snowdog/wombat`
|
20 | 2. Create content following [Content structure](#content-structure) description.
|
21 | 2. Add `"dev": "wombat dev"` to `package.json` scripts section
|
22 | 3. Run `yarn dev` and enjoy working with your new API
|
23 |
|
24 | ## Serverless deployment
|
25 | This guide is for [ZEIT Now](https://zeit.co/docs/v2/deployments/official-builders/node-js-now-node/), but setting up any other serverless env looks simillar.
|
26 |
|
27 | 1. In `package.json` add automatic DB building after installing dependecies
|
28 | ```
|
29 | "scripts": {
|
30 | "postinstall": "wombat build",
|
31 | "dev": "wombat dev"
|
32 | }
|
33 | ```
|
34 | 2. Define new builds and routes in `now.json` acording to [the example](./examples/now/now.json)
|
35 | 3. Copy [collection.js](./examples/now/collection.js) and [entity.js](./examples/now/entity.js) from examples
|
36 | 4. Deploy your app via `now`
|
37 |
|
38 | ## Config options
|
39 | ```js
|
40 | {
|
41 | "defaultLang": "en", // Fallback language when request is send without `lang` query param.
|
42 | "allowedOrigins": [], // List of domains used to set Access-Control-Allow-Origin (CORS) response header
|
43 | "dev": {
|
44 | "port": "3000", // Port used by the dev web server to listen for requests
|
45 | "build": true // Determines if new "database" file should be build from files before dev server will be started.
|
46 | }
|
47 | }
|
48 | ```
|
49 |
|
50 | ## Content structure
|
51 | All content is kept in `/content` directory.
|
52 | Inside you need to define supported languages. For example, we want to have content just in English, so it will be `/content/en`.
|
53 |
|
54 | Wombat supports two data types:
|
55 | ### Collections
|
56 | Designed to store sets of similar data, like blog posts, authors, job offers etc.
|
57 | - Collections are stored in `collection` directory inside each language.
|
58 | - Each collection and item of collection needs to be added as a directory.
|
59 | - Every property of an item collection needs to be a separate JSON or Markdown file.
|
60 |
|
61 | ### Entities
|
62 | Created to keep a single object like a landing page content or global configuration.
|
63 | - Entities are stored in `entity` directory inside each language.
|
64 | - Each entity needs to be added as a directory.
|
65 | - Every property of entity needs to be a separate JSON or Markdown file.
|
66 | - You can define the relation between entity and collection.
|
67 |
|
68 | ### How to define a relation between entity and collection?
|
69 | Create new JSON file inside entity directory to define relation:
|
70 | ```js
|
71 | {
|
72 | "query": {
|
73 | "name": "collectionName", // (required) collection name
|
74 | "sortBy": "title", // prop name used for sorting
|
75 | "sort": "desc", // `asc` is default - `sortBy` required to use it
|
76 | "limit": 2, // limit numer of returned items
|
77 | "page": 1, // page number
|
78 | "perPage": 100, // numer of items per page
|
79 | "items": ["award", "about", "partner"], // Array of collection items IDs. Items order is preserved.
|
80 | "props": ["id", "content"] // return only selected object props
|
81 | }
|
82 | }
|
83 | ```
|
84 |
|
85 | ### Example content tree
|
86 | ```
|
87 | content
|
88 | └── en
|
89 | ├── collection
|
90 | | └── blog
|
91 | | └── why-wombat-poop-is-cube
|
92 | | | ├── content.md
|
93 | | | ├── featured-image.json
|
94 | | | └── title.json
|
95 | | └── things-you-dont-know-about-wombats
|
96 | | ├── content.md
|
97 | | ├── featured-image.json
|
98 | | ├── form-config.json
|
99 | | └── title.json
|
100 | └── entity
|
101 | └── home
|
102 | ├── blog-posts.json
|
103 | ├── about.md
|
104 | └── hero-banner.json
|
105 | ```
|
106 | ## API
|
107 | ### `/entity`
|
108 | Retrieve an entity item.
|
109 |
|
110 | **Example:**
|
111 | To get `home` entity send request to `/entity?name=home`.
|
112 |
|
113 | **URL params:**
|
114 | - `name` - (required) Name of entity
|
115 | - `lang` - Return content in given lang.
|
116 |
|
117 | ### `/collection`
|
118 | Retrieve the whole collection as array.
|
119 |
|
120 | **Examples:**
|
121 | #### Whole collection
|
122 | ```
|
123 | /collection?name=blog
|
124 | ```
|
125 |
|
126 | #### Whole collection, but only title and content
|
127 | ```
|
128 | /collection?name=blog&props=title,title
|
129 | ```
|
130 |
|
131 | #### Only items selected by ID
|
132 | ```
|
133 | /collection?name=blog&items=why-wombat-poop-is-cube,things-you-dont-know-about-wombats
|
134 | ```
|
135 |
|
136 | #### Two items from collection sorted by title descending
|
137 | ```
|
138 | /collection?name=blog&limit=2&sortBy=title&sort=desc
|
139 | ```
|
140 |
|
141 | #### Items from second page, up to five per page
|
142 | ```
|
143 | /collection?name=blog&page=2&perPage=5
|
144 | ```
|
145 |
|
146 | **URL params:**
|
147 | - `name` - (required) Name of collection.
|
148 | - `lang` - Return content in given lang.
|
149 | - `sortBy` - Prop name used for sorting.
|
150 | - `sort` - `asc` is default - `sortBy` required to use it.
|
151 | - `limit` - Limit numer of returned items.
|
152 | - `page` - Page number.
|
153 | - `perPage` - Numer of items per page.
|
154 | - `items` - Comma separated list of collection items IDs. Items order is preserved.
|
155 | - `props` - Comma separated list of selected object props, GraphQL-like.
|