A simple CRUD REST backend so you can quickly prototype your front-end
Simply speaking, Dummy-backend is a zero-configuration REST backend that creates the resource (aka. REST endpoint) when you request it.
Lets say, you need to create a product record, just make a POST request the http://localhost:8080/product
endpoint, the backend will create a product
JSON record and return it.
You can then retrieve this record through a GET call to http://localhost:8080/product/<id>
request or modify it via PUT on http://localhost:8080/product/<id>
(and delete it, replace it, paginate it or upload a file…)
You don’t have to configure anything on the backend, no product table to create, no form… The server will create and persist tables and records as you need them while respecting HTTP REST best practices.
You can create, update, delete, get, replace, list (including query, sorting, pagination, filter) using the standard CRUD requests you know (see below).
Once you’re satified with your solution, you can start building a backend that matches your features and not the opposite.
Do not use Dummy-backend in production, it is not secure nor performant enough for that. It is meant to be used for prototyping only.
Clone this repository
git clone git@github.com:brigalabs/dummy-backend.git
Install the dependencies using yarn
cd dummy-backend
yarn
Run the server using yarn start
yarn start
The start call accepts the following arguments:
argument | alias | description | default |
---|---|---|---|
–port | -p | serving port | 8080 |
–file | -f | filename where data is persisted | database.json |
–delay | -d | delay prior to sending response | 200 |
–hostname | -n | hostname for serving | localhost |
So if you wanted to load the data stored in the file foo.json
on port 8007
you’d use the following command:
$ yarn start -d 150 -n 192.168.1.130 -f foo.json -p 8007
yarn run v1.12.3
...
[4/17/2020, 12:56:52 PM] Using port 8007
[4/17/2020, 12:56:52 PM] Database file is foo.json
[4/17/2020, 12:56:52 PM] Response delay is set to 150 ms
[4/17/2020, 12:56:52 PM] Serving hostname is set to 192.168.1.130
[4/17/2020, 12:56:52 PM] Serving request at http://192.168.1.130:8007
[4/17/2020, 12:56:52 PM] Loading data from foo.json ...
[4/17/2020, 12:56:52 PM] Loading data done.
By default the server will run on port 8080 on localhost. The convention is having the resource name as the first part of the URL followed by its optional ID:
http://localhost:8080/<resource>/<resource ID>
For example, if you wanted to interact with a user
resource, you would use the following URLs:
Operation | Method | URL | description |
---|---|---|---|
Get | GET | /user/123 | return the user with ID 123 |
Replace | PUT | /user/123 | replaces the user with ID 123 |
Update | PATCH | /user/123 | updates the user with ID 123 |
Delete | DELETE | /user/123 | delete the user with ID 123 |
Create | POST | /user | create a user (ID is autogenerated) |
Get many | GET | /user/ | return a list of users (more below) |
There is also additional “feature” endpoints. Feature endpoints don’t have a <resource>
root and start with a _
.
Operation | Method | URL | description |
---|---|---|---|
Upload | PUT | /_upload | uploads a file to the upload folder |
Get a File | GET | /_upload/upload_123.jpg | retrieve a previously uploaded file |
This is a cURL request creating a new user
curl --request POST "http://localhost:8080/users" \
--header "Content-Type: application/json" \
--data '{"name": "John Doe"}'
And the created user as a JSON response (HTTP/1.1 200 OK
):
{
"status": "success",
"data": {
"name": "Jonh Doe",
"id": "9b3521a4-0e08-471b-8434-19fcb2cc5899",
"createdAt": "2021-03-29T14:03:42.293Z",
"updatedAt": "2021-03-29T14:03:42.293Z"
}
}
Every object created will be augmented with 3 attributes:
id
: The uniq identifier, a UUID string like "d7699f21-902e-4d10-bf3c-e6c74c99f310"
createdAt
: A ISO date string like "2021-03-29T13:28:59.013Z"
updatedAt
: A ISO date string like "2021-03-29T13:28:59.013Z"
Update will combine the data provided with the existing record.
It will also update the updatedAt
to reflect current date.
Note that, when updating, the object needs to exist or you’ll get a 404 response.
This is an example of updating a user adding an age field:
curl --request PATCH "http://localhost:8080/users/9b3521a4-0e08-471b-8434-19fcb2cc5899" \
--header "Content-Type: application/json" \
--data '{"age": "32"}'
JSON response would be:
{
"status": "success",
"data": {
"name": "John Doe",
"id": "9b3521a4-0e08-471b-8434-19fcb2cc5899",
"createdAt": "2021-03-29T14:03:42.293Z",
"updatedAt": "2021-03-29T14:08:44.050Z",
"age": "32"
}
}
Replaces an existing record (beside it’s ID) with the data provided. Every missing
attribute will be removed from the record.
It will also update the updatedAt
to the current date.
Note that, when updating, the object needs to exists or you’ll get a 404 response.
For example, let’s replace our John Doe user by Jane Roe:
curl --request PUT "http://localhost:8080/users/9b3521a4-0e08-471b-8434-19fcb2cc5899" \
--header "Content-Type: application/json" \
--data '{"name": "Jane Roe"}'
The server will return you the replaced record.
{
"status": "success",
"data": {
"name": "Jane Roe",
"createdAt": "2021-03-29T15:05:07.248Z",
"id": "a8c9e739-dff3-4bdb-825c-81595d8e411f",
"updatedAt": "2021-03-29T15:06:03.476Z"
}
}
Note that since this is a replace operating, only the provided data is stored, you the
user had an age
attribute before, it is now gone.
Returns a given record, the object needs to exists or you’ll get a 404 response.
To retrieve a user:
curl --request GET "http://localhost:8080/users/9b3521a4-0e08-471b-8434-19fcb2cc5899" \
--header "Content-Type: application/json"
JSON response would be:
{
"status": "success",
"data": {
"name": "John Doe",
"id": "9b3521a4-0e08-471b-8434-19fcb2cc5899",
"createdAt": "2021-03-29T14:03:42.293Z",
"updatedAt": "2021-03-29T14:08:44.050Z",
"age": "32"
}
}
Deletes a given record. When deleting, the record needs to exists or you’ll get a 404 response.
Example, deleting a record that does not exist (HTTP/1.1 404 Not Found):
curl --request DELETE "http://localhost:8080/users/does-not-exist" \
--header "Content-Type: application/json"
{
"status": "error",
"error": "not_found",
"message": "[DELETE] /users/does-not-exist does not exist."
}
Example when the record exist:
curl --request DELETE "http://localhost:8080/users/9b3521a4-0e08-471b-8434-19fcb2cc5899" \
--header "Content-Type: application/json"
JSON response contains the deleted data under the data
attribute:
{
"status": "success",
"data": {
"name": "John Doe",
"id": "9b3521a4-0e08-471b-8434-19fcb2cc5899",
"createdAt": "2021-03-29T14:03:42.293Z",
"updatedAt": "2021-03-29T14:08:44.050Z",
"age": "32"
}
}
Listing often allows for a few additional actions like, pagination, filtering and sorting. So, here you go…
For example, if you wanted to retrieve all the users (in a paginated fashion):
curl --request GET "http://localhost:8080/users/"
This is the response you could get:
{
"status": "success",
"data": [
{
"name": "Darragh Lake",
"id": "63a12046-7337-4c3c-8ddb-7331808224c2",
"createdAt": "2021-03-29T14:00:05.548Z",
"updatedAt": "2021-03-29T14:00:05.548Z"
},
{
"name": "Frank Stevenson",
"id": "9a205d6c-f336-4391-9097-33003104dbaf",
"createdAt": "2021-03-29T14:00:29.256Z",
"updatedAt": "2021-03-29T14:00:29.256Z"
},
{
"name": "Caden Glover",
"id": "c864d1e4-104c-4a2a-93bb-7893edab881b",
"createdAt": "2021-03-29T14:02:01.866Z",
"updatedAt": "2021-03-29T14:02:01.866Z"
},
{
"name": "Claude Washington",
"id": "40f92c97-f88c-49d3-8359-8b2816e26833",
"createdAt": "2021-03-29T14:02:43.757Z",
"updatedAt": "2021-03-29T14:02:43.757Z"
},
{
"name": "Ayah Robbin",
"id": "d4aba19a-4044-4ca1-bb7c-532d44e57b96",
"createdAt": "2021-03-29T14:03:24.631Z",
"updatedAt": "2021-03-29T14:03:24.631Z"
},
{
"name": "Alicia Riggs",
"id": "81f38d70-910a-444d-b7e2-6b7b0efa3462",
"createdAt": "2021-03-29T14:05:48.843Z",
"updatedAt": "2021-03-29T14:05:48.843Z"
},
{
"name": "Hermione Cruz",
"createdAt": "2021-03-29T15:05:07.248Z",
"id": "a8c9e739-dff3-4bdb-825c-81595d8e411f",
"updatedAt": "2021-03-29T15:06:03.476Z"
}
],
"total": 7,
"pageSize": 10,
"page": 0,
"sortBy": "",
"sortDirection": "ASC",
"filters": []
}
Every listing endpoint accepts the following query arguments:
argument | description | example | default |
---|---|---|---|
page | page number starting at 0 | ?page=0 | 0 |
pageSize | number of items per page | ?pageSize=5 | 10 |
sortBy | attribute to sort the listing by | ?sortBy=createdAt | - |
sortDirection | sorting direction when sortBy is provided | ?sortDirection=DESC | ASC |
filter | filter records | ?filter=name:john&filter=createdAt[gte]:2020-05-01 | - |
If you wanted to obtain the second page, with 2 records per page and sorted by name:
curl --request GET "http://localhost:8080/users/?pageSize=2&page=2&sortBy=name"
You’d obtain the following result:
{
"status": "success",
"data": [
{
"name": "Darragh Lake",
"id": "63a12046-7337-4c3c-8ddb-7331808224c2",
"createdAt": "2021-03-29T14:00:05.548Z",
"updatedAt": "2021-03-29T14:00:05.548Z"
},
{
"name": "Frank Stevenson",
"id": "9a205d6c-f336-4391-9097-33003104dbaf",
"createdAt": "2021-03-29T14:00:29.256Z",
"updatedAt": "2021-03-29T14:00:29.256Z"
}
],
"total": 7,
"pageSize": 2,
"page": 2,
"sortBy": "name",
"sortDirection": "ASC",
"filters": []
}
You can add as many filter as you want on the query. Every filter is composed as follow:
filter=<attribute>[operator]:<value>&filter=<attribute>[operator]:<value>&...
operator | description |
---|---|
eq | equal, case sensitive (default) |
gt | greater than |
gte | greater than or equal |
lt | lesser than |
lte | lesser than or equal |
reg | regular expression |
has | contains specified value (case insensitive) |
for example, you could filter the list of user with only the value
"Lake"
:
curl --request GET "http://localhost:8080/users/?pageSize=2&filter=name[has]:lake"
to get the following result:
{
"status": "success",
"data": [
{
"name": "Darragh Lake",
"id": "63a12046-7337-4c3c-8ddb-7331808224c2",
"createdAt": "2021-03-29T14:00:05.548Z",
"updatedAt": "2021-03-29T14:00:05.548Z"
}
],
"total": 1,
"pageSize": 2,
"page": 0,
"sortBy": "",
"sortDirection": "ASC",
"filters": [{ "attribute": "name", "operator": "has", "value": "Lake" }]
}
Since the listing endpoint accepts arguments for pagination, it makes sense to receive a response that allows you to display proper pagination.
A call to a listing endpoint of users would return:
{
"status": "success",
"data": [
{
"name": "Ayah Robbin",
"id": "d4aba19a-4044-4ca1-bb7c-532d44e57b96",
"createdAt": "2021-03-29T14:03:24.631Z",
"updatedAt": "2021-03-29T14:03:24.631Z"
},
{
"name": "Caden Glover",
"id": "c864d1e4-104c-4a2a-93bb-7893edab881b",
"createdAt": "2021-03-29T14:02:01.866Z",
"updatedAt": "2021-03-29T14:02:01.866Z"
}
],
"total": 7,
"pageSize": 2,
"page": 0,
"sortBy": "id",
"sortDirection": "DESC",
"filters": []
}
By default the database is stored in memory and is backed up to
every one seconds in a file (default to database.json
).
The database is loaded back in memory when the server starts.