README ¶
Backend for a mini selfmade headless CMS using Fiber
Content
Usage
You can run this package on its own by setting the .env accordingly, for exapmle with a Atlas hosted MongoDB Cluster (the .env file variables are used by both the docker-compose and the fiber-backend), but using the docker-compose.yaml is the easiest way to deploy all dependencies on a server.
Follow these steps:
- Install docker and docker-compose
- Download .env file
$ sudo wget -O .env https://raw.githubusercontent.com/D-Bald/fiber-backend/main/.env.sample
- Set the
DB_HOST
variable in the .env file to the name of the docker service (in this docker-compose.yaml the service is namedmongodb
). If you use a Atlas hosted MongoDB database, set this variable toATLAS
. Also check environment variables like ports, database name, user and passwor and PLEASE changeSECRET
andADMIN_PASSWORD
. - Download docker-compose.yaml file
$ sudo wget -O docker-compose.yaml https://raw.githubusercontent.com/D-Bald/fiber-backend/main/docker-compose.yaml
- Execute the following commands in the root directory of docker-compose.yaml:
- To get the containers up and running execute:
$ docker-compose up -d
- To stop the containers execute:
$ docker-compose down -v
- To get the containers up and running execute:
This setup will create and start three docker containers:
The data is persistent over multiple up
and down
cycles using docker volumes.
Check the database setup with mongo-express on http://localhost:8081
.
API
Endpoint | Method | Authentification required | Response Fields* | Description |
---|---|---|---|---|
/api |
GET |
✗ | Health-Check | |
/api/auth/login |
POST |
✗ | token , user |
Sign in with username or email (identity ) and password . On success returns token and user. |
/api/role |
GET |
✓ | role |
Returns all existing roles. |
POST |
✓ (admin) | role |
Creates a new Role. | |
/api/role/:id |
PATCH |
✓ (admin) | result |
Updates role with id id . |
DELETE |
✓ (admin) | result |
Deletes role with id id . Also removes references to this role in user and content type documents. |
|
/api/user |
GET |
✓ | user |
Return users present in the users collection. |
POST |
✗ | token , user |
Creates a new user. Specify the following attributes in the request body: username , email , password , names . On success returns token and user. |
|
/api/user/:id |
PATCH |
✓ | result |
Updates user with id id . If you want to update role , you have to be authenticated with a admin-user. |
DELETE |
✓ | result |
Deletes user with id id .Specify user´s password in the request body. |
|
/api/contenttypes |
GET |
✗ | contenttype |
Returns all content types present in the contenttypes collection. |
POST |
✓ (admin) | contenttype |
Creates a new content type. Specify the following attributes in the request body: typename , collection , field_schema . |
|
/api/contenttypes/:id |
GET |
✗ | contenttype |
Returns content type with id :id . |
PATCH |
✓ (admin) | result |
Updates content type with id :id . |
|
DELETE |
✓ (admin) | result |
Deletes content type with id :id . Watch out: Also deletes all content entries with this content type. |
|
/api/:content |
GET |
✗ | content |
Returns content entries of the content type, where content is the corresponding collection. By convention this should be plural of the typename .For the previous example: content has to be set to events . |
POST |
✓ (depends on content type permissions) | content |
Creates a new content entry of the content type, where content is the corresponding collection.Specify the following attributes in the request body: title (string), published (bool), fields (key-value pairs: field name - field value). |
|
/api/:content/:id |
PATCH |
✓ (depends on content type permissions) | result |
Updates content entry with id id of the content type, where content is the corresponding collection. |
DELETE |
✓ (depends on content type permissions) | result |
Deletes content entry with id id of the content type, where content is the corresponding collection. |
* status
and message
are returned on every request.
Workflows
Roles
Two roles are initiated out of the box:
{
"tag":"default",
"name":"User"
}
{
"tag":"admin",
"name":"Administrator"
}
The default role is given any new user. The admin role is used as general access role and on start a new adminUser is created, if no other user with role tag admin is found. By changing the name
you can decide how an admin is called and which default role is given any new user.
Warning: Removing these roles or changing the tag causes trouble because user creation will fail due to missing default role and you can loose your last admin access user. On the next start a new admin role and adminUser is created, but this leads to a redundant adminUser and you can not reliably login with real a admin access. This issue can be solved by deleting the adminUser that has not the admin role, but it can be hard to debug.
Just one GET
endpoint exists, which returns all roles. There is no use for the data of a singe role.
Example JSON request body:
// POST or PATCH
{
"tag":"moderator",
"Name":"Moderator"
}
Create content and content types
The content types event and blogpost are preset and you can start adding entries on those routes (/api/events
or /api/blogposts
). Events have custom fields description and date whereas blogposts come with description and text. By convention the collection should be plural of the typename.
If you want to create a custom content type, first use the /api/contenttypes
endpoint, because the /api/:content
route is validated by a lookup in the contenttypes
collection. The mongoDB collections for new types are created automatically on first content insertion.
The GET
Endpoint is not protected by any middleware. POST
, PATCH
and DELETE
endoints for any content are protected and you have to specify the roles that users have to have to perform each method (see example below) in the content types Permissions
object. Users with admin role tag can perform any method on any content. Both default contenttypes (event and blogpost) set all method permissions to the default role.
The last attribute for a new content type, field_schema, is a list of key-value pairs specifying name and type of fields, that an content entry of this content type should have.
Exapmle JSON request body:
{
"typename": "protected-admin-test",
"collection": "protected-admin-test-entries",
"permissions": {
"POST": [
"Moderator"
],
"PATCH": [
"Moderator"
],
"DELETE": [
"Moderator"
]
},
"field_schema": {
"text_field": "string"
}
}
The last attribute for a new content entry, fields is a list of key-value pairs specifying name and value of fields, that should match the field_schema of the corresponding content type. A schema validation is not yet implemented.
Example JSON request body:
{
"title": "Blogpost Test",
"published": false,
"tags": [
"foo",
"bar"
],
"fields": {
"description": "Hello world",
"date": "2021-04-08T12:00:00+02:00"
}
}
Update content and content types
To update an array, like tags of content entries or permissions of content types, the whole array has to be sent. On this structure the update behaves more like a PUT
method.
To update custom fields of content entries you have to specify it as an object in the request body.
Example JSON request body:
{ "fields": {"description": "foo bar"} }
Preset fields can be reached directly. Example JSON request body:
{
"tags": ["foo", "bar"],
"published": true
}
Create users
The admin user adminUser is preset with the password ADMIN_PASSWORD
from the .env file in the root direcory of the executable.
Anybody can create a new user. The role is automatically set to user.
Example JSON request body:
{
"username": "TestUser",
"email": "unique@mail.com",
"password":"123",
"names":"names",
}
Update users
A user can edit the own data i.e. username, email, password, names.
Every user with role admin can edit any other user and particularly can edit the field role of any user. Roles must be updated as array containing all roles as single strings.
Example JSON request body:
{
"username": "John Doe",
"roles": ["User","Moderator"]
}
Query users and content entries by route parameters
To get all Users or all content entries of one content type, just use the bare API GET
endpoint (example 1). To search for Users and content entries with certain properties, a query string can be added to the API endpoint. The query string begins with ?
. Each search parameter has the structure key=value
and is case sensitive. Each document has a unique ID, that can be used to query for a single result (example 2). Multiple parameters are seperated by &
(example 3). Custom fields of content entries can be queried directly so don't use dot-notation or similar (example 4). Only the whole field value is matched, so submatches are not supported. Queries for single elements of array fields like 'tags' are possible (example 5). In queries with multiple array elements, the query values currently have to have the same order as in the database and can not be a subset of the stored ones(example 6). Therefore queries with single values are recommended.
Examples:
# 1
/api/events
# 2
/api/user?_id=609273e9f17aa49bcd126418
# 3.
/api/blogposts?title=Title&published=false
# 4.
/api/events?place=home
# 5.
/api/blogposts?tags=foo
# 6.
/api/events?tags=foo,bar
Example 6 currently only returns documents with a full match on tags like:
{ "tags": ["foo", "bar"] }
TODO
- Fix Issue: Dates cannot be queried, because the
+
sign in a query string is treated as empty space. Maybe by escaping + if the parameter value is send in""
- Add idiomatic Endpoints for common getters and setters like: Set title, set username set names, set password...
- Implement permission control over user, roles and content types endpoints
- Issue: standard_init_linux.go:219: exec user process caused: no such file or directory on
docker-compose up
when using the :latest image created by workflow CI on GitHub Actions => workflow currently disabled and a locally on an ubuntu server built image is used in the docker-compose.yaml. - Implement file upload
- Validate field_schema on content entry creation (https://docs.mongodb.com/manual/core/schema-validation/)
Thanks to...
Documentation ¶
There is no documentation for this package.