Skip to content

brigalabs/dummy-backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

57 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dynamic REST API for protyping

Simply speaking, Dummy-backend is a zero-configuration REST backend that creates the resource (aka. REST endpoint) when you request it.

Why would I need that?

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...)

  • No database to setup
  • No proxy server
  • No VM
  • No authentication

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.

Warning

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.

Install

Clone this repository

git clone [email protected]:brigalabs/dummy-backend.git

Install the dependencies using yarn

cd dummy-backend
yarn

Run the server using yarn start

yarn start

Options

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.

Interactions

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

Create a New Record

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 a Record

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"
  }
}

Replace a Record

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.

Get A Single Record

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"
  }
}

Delete a Record

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

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": []
}

Listing query arguments

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": []
}

Listing 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" }]
}

Listing Response

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": []
}

Persistence

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.

About

A simple CRUD REST backend so you can quickly prototype your front-end

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published