Code Monkey home page Code Monkey logo

caffeine's Introduction

caffeine - minimum viable backend

A very basic REST service for JSON data - enough for prototyping and MVPs!

Features:

  • no need to set up a database, all data is managed automagically*
  • REST paradigm CRUD for multiple entities/namespaces
  • JWT authentication
  • realtime notifications (HTTP/SSE)
  • schema validation
  • autogenerates Swagger/OpenAPI specs
  • search using jq like syntax (see https://stedolan.github.io/jq/manual/)
  • CORS enabled
  • easy to deploy as container

Currently supports:

  • in memory database (map)
  • sqlite
  • postgres
  • filesystem storage

For a sample Vue app using caffeine see: https://gist.github.com/calogxro/6e601e07c2a937df4418d104fb717570

How to

Simply start the server with:

go run caffeine.go

optional params are:

Usage of caffeine:
  -AUTH_ENABLED=false: enable JWT auth
  -DB_TYPE="memory": db type to use, options: memory | postgres | fs | sqlite
  -DB_PATH="./data": path of the file storage root or sqlite database
  -IP_PORT=":8000": ip:port to expose
  -PG_HOST="0.0.0.0": postgres host (port is 5432)
  -PG_PASS="": postgres password
  -PG_USER="": postgres user

Store a new "user" with an ID and some json data:

> curl -X POST -d '{"name":"jack","age":25}'  http://localhost:8000/ns/users/1
{"name":"jack","age":25}

the value will be validated, but it could be anything (in JSON!)

retrieve later with:

> curl http://localhost:8000/ns/users/1
{"name":"jack","age":25}

All operations

Insert/update

> curl -X POST -d '{"name":"jack","age":25}'  http://localhost:8000/ns/users/1
{"name":"jack","age":25}

Delete

> curl -X DELETE http://localhost:8000/ns/users/1

Get by ID

> curl http://localhost:8000/ns/users/1
{"name":"jack","age":25}

Get all values for a namespace

> curl http://localhost:8000/ns/users | jq 
[
  {
    "key": "2",
    "value": {
      "age": 25,
      "name": "john"
    }
  },
  {
    "key": "1",
    "value": {
      "age": 25,
      "name": "jack"
    }
  }
]

Get all namespaces

> curl http://localhost:8000/ns
["users"]

Delete a namespace

> curl -X DELETE http://localhost:8000/ns/users
{}

Search by property (jq syntax)

> curl http://localhost:8000/search/users?filter="select(.name==\"jack\")"  | jq
{
  "results": [
    {
      "key": "1",
      "value": {
        "age": 25,
        "name": "jack"
      }
    }
  ]
}

JWT Authentication

There's a first implementation of JWT authentication. See documentation about JWT

Realtime Notifications

Using HTTP Server Sent Events (SSE) you can get notified when data changes, just need to listen from the /broker endpoint:

curl http://localhost:8000/broker

and for every insert or delete an event will be triggered:

{"event":"ITEM_ADDED","namespace":"test","key":"1","value":{"name":"john"}}
...
{"event":"ITEM_DELETED","namespace":"test","key":"1"}
...

Swagger/OpenAPI specs

After you add some data, you can generate the specs with:

curl -X GET http://localhost:8000/openapi.json

or you can just go to http://localhost:8000/swaggerui/ and use it interactively!

Schema Validation

You can add a schema for a specific namespace, and only correct JSON data will be accepted

To add a schema for the namespace "user", use the one available in schema_sample/:

curl --data-binary @./schema_sample/user_schema.json http://localhost:8000/schema/user

Now only validated "users" will be accepted (see user.json and invalid_user.json under schema_sample/)

Run as container

docker build -t caffeine .

and then run it:

docker run --publish 8000:8000 caffeine

Run with Postgres

First run an instance of Postgres (for example with docker):

docker run -e POSTGRES_USER=caffeine -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres:latest

Then run caffeine with the right params to connect to the db:

DB_TYPE=postgres PG_HOST=0.0.0.0 PG_USER=caffeine PG_PASS=mysecretpassword go run caffeine.go

(params can be passed as ENV variables or as command-line ones)

A very quick to run both on docker with docker-compose:

docker-compose up -d

caffeine's People

Contributors

adsk-nadeaup avatar annoybot avatar calogxro avatar ehsundar avatar hezhizhen avatar rehacktive avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

caffeine's Issues

CI/CD and built releases

We can add a circle ci or travis to this project. so that:

  • verify that tests are passing
  • measure test coverage
  • publish binary releases
  • publish to package managers (far future)

client generation?

Great project!

I plan to use this eventually, but if i'm going to design a service, I need both client and server. I'd rather not have to spec out both if possible.

It'd be cool if you could generate a swagger or protobuf definition from existing data and schema. I'm sure that's a lot of work but it'd be much more powerful to have strictly typed objects in the client.

File based database

I want to develop a feature to use file system as data storage. It is similar to the mem implementation except that the data is persisted easily on disk. To be honest, I think pg is kinda overkill.

In terms of security (e.g. namespaces named like /test/../../../ssh.conf) we should prohibit names with slashes and dots. Although if caf is used inside a container (mounted directory) this problem won't be a valid concern anymore...

Wrong status code for not existing namespace

Requests (GET, DELETE) for not existing namespaces return a 400 error: a 404 error would be expected.
Moreover, on deleting a not existing namespace two objets are returned: {"error": "not found"} and {}.

$ curl localhost:8000/ns
[]

GET

$ curl -v localhost:8000/ns/todos
*   Trying 127.0.0.1:8000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /ns/todos HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Content-Type: application/json
< Vary: Origin
< Date: Fri, 19 Nov 2021 14:27:00 GMT
< Content-Length: 22
< 
* Connection #0 to host localhost left intact
{"error": "not found"}

DELETE

$ curl -v -X DELETE localhost:8000/ns/todos
*   Trying 127.0.0.1:8000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> DELETE /ns/todos HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Content-Type: application/json
< Vary: Origin
< Date: Fri, 19 Nov 2021 14:31:01 GMT
< Content-Length: 24
< 
* Connection #0 to host localhost left intact
{"error": "not found"}{}

Wrong status code on not found

You can reproduce it like this:

$ curl -v http://localhost:8000/ns/users/1
*   Trying ::1:8000...
* Connected to localhost (::1) port 8000 (#0)
> GET /ns/users/1 HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.77.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Content-Type: application/json
< Vary: Origin
< Date: Thu, 18 Nov 2021 10:58:22 GMT
< Content-Length: 22
< 
* Connection #0 to host localhost left intact
{"error": "not found"}

Need to change status to 404.

Lets add a few static routes for auth

Now that we have JWT implemented here, I think we can add a few routes to achieve these:

  • register new user (signup)
    • full name
    • username
    • password
  • get a jwt with expire time
    • username
    • password
  • refresh jwt
    • token (as header)

If you agreed, I would open a MR soon.

Please note that we need to sacrifice user model flexibility to implement a reliabe API. This flaw can be remedied in future MRs.

Auto JWT

We can generate JWT secrets at startup and store them in our storage. JWT would be out of the box.

(I know storing secrets in storage is not recommended. but this program is not intended to be used in production environments.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.