Git Product home page Git Product logo

weld's Introduction

Weld

Full fake REST API generator.

weldmock' current version badge Build Status codecov

This project is heavily inspired by json-server, written with rust.

Synopsis

Our first aim is to generate a fake api from the given data source (JSON). It may have bugs, missing features but if you contribute they all will be fixed.

Version CHANGELOG

Techs

Installation

  1. Download and install Rust from here
  2. Download and install Cargo from here
  3. Clone and run the project.
git clone https://github.com/serayuzgur/weld.git
cd weld
cargo run

Usage

Running

Executable can take configuration path otherwise it will use default ./weld.json. If we take project folder as root, commands should look like one of these. If you you use cargo build --release version change debug with release.

./target/debug/weld  
./target/debug/weld weld.json
./target/debug/weld <path_to_config>.json

./target/release/weld  
./target/release/weld weld.json
./target/release/weld <path_to_config>.json

Configuration

Configuration file is a very simple json file which is responsible to hold server and database properties.

{
    "server": {
        "host": "127.0.0.1",
        "port": 8080
    },
    "database": {
        "path": "db.json"
    }
}

Database

Database is a simple json file.

{
    "owner": {
        "name": "seray",
        "surname": "uzgur"
    },
    "posts": [
        {
            "author": {
                "name": "seray",
                "surname": "uzgur"
            },
            "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
            "id": 1,
            "tags": [
                {
                    "id": 1,
                    "name": "tech"
                },
                {
                    "id": 2,
                    "name": "web"
                }
            ],
            "title": "Rust Rocks!"
        },
        {
            "author": {
                "name": "kamil",
                "surname": "bukum"
            },
            "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
            "id": 2,
            "tags": [
                {
                    "id": 1,
                    "name": "tech"
                },
                {
                    "id": 2,
                    "name": "web"
                }
            ],
            "title": "TypeScript is Awesome"
        }
    ],
    "version": "10.1.1"
}

Here the owner and posts are tables. They can be empty arrays/objects but they must exist as is.

NOTE : id: Column is a must, all parsing uses it.

API

Api usage is pretty simple. For now it does not support filters one other query params. Here is the list of the calls you can make with examples.

  • Get List <host>:<port>/<table> GET
  • Get Record <host>:<port>/<table>/<id> GET
  • Insert Record <host>:<port>/<table> POST
  • Update Record <host>:<port>/<table>/<id> PUT
  • Delete Record <host>:<port>/<table>/<id> DELETE
  • Get Nested <host>:<port>/<table>/<id><field>/<id>... GET

Get List

url: http://127.0.0.1:8080/posts 
method: GET
body: empty

response: 
[
  {
    "author": "serayuzgur",
    "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
    "id": 1,
    "title": "Rust Rocks!"
  },
  {
    "author": "kamilbukum",
    "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
    "id": 2,
    "title": "TypeScript is Awesome"
  }
]

Get Record

url: http://127.0.0.1:8080/posts/1 
method: GET
body: empty

response: 
{
    "author": {
        "name": "seray",
        "surname": "uzgur"
    },
    "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
    "id": 1,
    "tags": [
        {
            "id": 1,
            "name": "tech"
        },
        {
            "id": 2,
            "name": "web"
        }
    ],
    "title": "Rust Rocks!"
}

Insert Record

url: http://127.0.0.1:8080/posts
method: POST
body:
{
  "author": {
    "name": "hasan",
    "surname": "mumin"
  },
  "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
  "id": 3,
  "tags": [
    {
      "id": 1,
      "name": "tech"
    },
    {
      "id": 2,
      "name": "web"
    }
  ],
  "title": "KendoUI Rocks!"
}

response: 
{
  "author": {
    "name": "hasan",
    "surname": "mumin"
  },
  "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
  "id": 3,
  "tags": [
    {
      "id": 1,
      "name": "tech"
    },
    {
      "id": 2,
      "name": "web"
    }
  ],
  "title": "KendoUI Rocks!"
}

Update Record

url: http://127.0.0.1:8080/posts/3
method: PUT
body:
{
  "author": {
    "name": "hasan",
    "surname": "mumin"
  },
  "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
  "id": 3,
  "tags": [
    {
      "id": 1,
      "name": "tech"
    },
    {
      "id": 2,
      "name": "web"
    }
  ],
  "title": "KendoUI Rocks!"
}

response: 
{
  "author": {
    "name": "hasan",
    "surname": "mumin"
  },
  "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
  "id": 3,
  "tags": [
    {
      "id": 1,
      "name": "tech"
    },
    {
      "id": 2,
      "name": "web"
    }
  ],
  "title": "Angular Rocks!"
}

Delete Record

url: http://127.0.0.1:8080/posts/3
method: DELETE
body: empty

response: 
{
  "author": {
    "name": "hasan",
    "surname": "mumin"
  },
  "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
  "id": 3,
  "tags": [
    {
      "id": 1,
      "name": "tech"
    },
    {
      "id": 2,
      "name": "web"
    }
  ],
  "title": "KendoUI Rocks!"
}

Get Nested

url: http://127.0.0.1:8080/posts/1/author
method: GET
body: empty

response:
{
    "name": "seray",
    "surname": "uzgur"
}
url: http://127.0.0.1:8080/posts/1/author/name
method: GET
body: empty

response:
"seray"
url: http://127.0.0.1:8080/posts/1/tags/1
method: GET
body: empty

response:
{
    "id": 1,
    "name": "tech"
}

Query API

Field selection

Give the API consumer the ability to choose returned fields. This will also reduce the network traffic and speed up the usage of the API.

GET /cars?fields=manufacturer,model,id,color
Paging
GET /cars?_offset=10&_limit=5
  • Add _offset and _limit (an X-Total-Count header is included in the response).

  • To send the total entries back to the user use the custom HTTP header: X-Total-Count.

  • Content-Range offset – limit / count.

    • offset: Index of the first element returned by the request.

    • limit: Index of the last element returned by the request.

    • count: Total number of elements in the collection.

  • Accept-Range resource max.

  • resource: The type of pagination. Must remind of the resource in use, e.g: client, order, restaurant, …

  • max : Maximum number of elements that can be returned in a single request.

Sorting
  • Allow ascending and descending sorting over multiple fields.
  • Use sort with underscore as _sort.
  • In code, descending describe as -, ascending describe as +.

GET /cars?_sort=-manufactorer,+model

Operators
  • Add _filter query parameter and continue with field names,operations and values separated by ,.
  • Pattern _filter=<fieldname><operation><value>.
  • Supported operations.
    • = equal
    • != not equal
    • < less
    • <= less or equals
    • > greater
    • >= greater or equals
    • ~= like
    • |= in (values must be separated with |

GET http://127.0.0.1:8080/robe/users?_filter=name=seray,active=true

Full-text search
  • Add _q.

GET /cars?_q=nissan

License

The MIT License (MIT) Copyright (c) 2017 Seray Uzgur

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

weld's People

Contributors

kbukum avatar serayuzgur avatar x-wera 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

weld's Issues

configuration module refactor

configuration module must care all wrappers (Optional, Result)
must have default values
must support static lazy init
Logs must be understandable

AccessControlAllowOrigin

Add the header AccessControlAllowOrigin::Any to src/service/mod.rs, in impl Service for RestService for the response. I did this to my local copy but don't feel like forking on GitHub and doing a PR for something so simple.

        let response = Response
          ::new()
          .with_header(AccessControlAllowOrigin::Any);

Do not forget to include the module at the top:

use hyper::header::AccessControlAllowOrigin;

filters, sorting, paging...

Field selection

  • Sometimes don’t need all attributes of a resource. Give the API consumer the ability to choose returned fields. This will also reduce the network traffic and speed up the usage of the API.

GET /cars?fields=manufacturer,model,id,color

Paging (Slice)

  • Add _offset and _limit (an X-Total-Count header is included in the response).

GET /cars?_offset=10&_limit=5

  • To send the total entries back to the user use the custom HTTP header: X-Total-Count.

  • Content-Range offset – limit / count.

    • offset: Index of the first element returned by the request.

    • limit: Index of the last element returned by the request.

    • count: Total number of elements in the collection.

  • Accept-Range resource max.

  • resource: The type of pagination. Must remind of the resource in use, e.g: client, order, restaurant, …

  • max : Maximum number of elements that can be returned in a single request.

Sorting

  • Allow ascending and descending sorting over multiple fields.
  • Use sort with underscore as _sort.
  • In code, descending describe as -, ascending describe as +.

GET /cars?_sort=-manufactorer,+model

Operators

  • Add _filter query parameter and continue with field names,operations and values separated by ,.
  • Pattern _filter=<fieldname><operation><value>.
  • Supported operations.
    • = equal
    • != not equal
    • < less
    • <= less or equals
    • > greater
    • >= greater or equals
    • ~= like
    • |= in (values must be separated with |

GET http://127.0.0.1:8080/robe/users?_filter=name=seray,active=true

Full-text search

  • Add _q.

GET /cars?_q=nissan

Support for all data types at all levels.

For ex.

{
    "owner": {
        "name": "seray",
        "surname": "uzgur"
    },
    "posts": [
        {
            "author": {
                "name": "seray",
                "surname": "uzgur"
            },
            "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
            "id": 1,
            "tags": [
                {
                    "id": 1,
                    "name": "tech"
                },
                {
                    "id": 2,
                    "name": "web"
                }
            ],
            "title": "Rust Rocks!"
        },
        {
            "author": {
                "name": "kamil",
                "surname": "bukum"
            },
            "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero.",
            "id": 2,
            "tags": [
                {
                    "id": 1,
                    "name": "tech"
                },
                {
                    "id": 2,
                    "name": "web"
                }
            ],
            "title": "TypeScript is Awesome"
        }
    ],
    "version": "10.1.1"
}

Can't build on Windows

I am new to Rust, so I apologize if this is a stupid issue to report. I tried to do cargo run on Windows and got a few errors. It worked fine on Ubuntu though.


  Compiling weldmock v0.0.1-alpha.5 (C:\BitBucket\Rust\weld-master)
     Running `rustc --crate-name weldmock src\main.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -Cembed-bitcode=no -C debuginfo=2 -C metadata=07215c868661c321 --out-dir C:\BitBucket\Rust\weld-master\target\debug\deps -C incremental=C:\BitBucket\Rust\weld-master\target\debug\incremental -L dependency=C:\BitBucket\Rust\weld-master\target\debug\deps --extern bytes=C:\BitBucket\Rust\weld-master\target\debug\deps\libbytes-2548d93e1fba7e01.rlib --extern futures=C:\BitBucket\Rust\weld-master\target\debug\deps\libfutures-77d46f9522c81dae.rlib --extern futures_cpupool=C:\BitBucket\Rust\weld-master\target\debug\deps\libfutures_cpupool-8fec00508ae16a84.rlib --extern hyper=C:\BitBucket\Rust\weld-master\target\debug\deps\libhyper-810c394286b9e558.rlib --extern lazy_static=C:\BitBucket\Rust\weld-master\target\debug\deps\liblazy_static-3058c6f12d44e685.rlib --extern rand=C:\BitBucket\Rust\weld-master\target\debug\deps\librand-5588f3c0ef422b0e.rlib --extern serde=C:\BitBucket\Rust\weld-master\target\debug\deps\libserde-9fb117223d51cdf7.rlib --extern serde_derive=C:\BitBucket\Rust\weld-master\target\debug\deps\serde_derive-3345c08c9809f3ee.dll --extern serde_json=C:\BitBucket\Rust\weld-master\target\debug\deps\libserde_json-2386744b445deb8c.rlib --extern slog=C:\BitBucket\Rust\weld-master\target\debug\deps\libslog-27db374df41a8f6f.rlib --extern slog_async=C:\BitBucket\Rust\weld-master\target\debug\deps\libslog_async-90ae84865c8b2898.rlib --extern slog_term=C:\BitBucket\Rust\weld-master\target\debug\deps\libslog_term-6ff45e9e118bb74d.rlib --extern time=C:\BitBucket\Rust\weld-master\target\debug\deps\libtime-4d0067c55314a829.rlib`
error[E0603]: enum `ErrorCode` is private
   --> src\database\query_api\filter.rs:5:24
    |
5   | use serde_json::error::ErrorCode::Message;
    |                        ^^^^^^^^^ private enum
    |
note: the enum `ErrorCode` is defined here
   --> C:\Users\Alan\.cargo\registry\src\github.com-1ecc6299db9ec823\serde_json-1.0.58\src\error.rs:176:1
    |
176 | pub(crate) enum ErrorCode {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: unused doc comment
  --> src\weld.rs:12:1
   |
12 | ///Initializes lazy statics.
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations
   |
   = note: `#[warn(unused_doc_comments)]` on by default
   = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion

warning: trait objects without an explicit `dyn` are deprecated
  --> src\service\utils.rs:13:22
   |
13 | type FutureBox = Box<futures::Future<Item = Response, Error = Error>>;
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn futures::Future<Item = Response, Error = Error>`
   |
   = note: `#[warn(bare_trait_objects)]` on by default

warning: trait objects without an explicit `dyn` are deprecated
  --> src\service\mod.rs:20:22
   |
20 | type FutureBox = Box<Future<Item = Response, Error = Error>>;
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn Future<Item = Response, Error = Error>`

error[E0624]: associated function `syntax` is private
  --> src\database\query_api\filter.rs:45:24
   |
45 |             Err(Error::syntax(error, 1, 1))
   |                        ^^^^^^ private associated function

error: aborting due to 2 previous errors; 3 warnings emitted

Some errors have detailed explanations: E0603, E0624.
For more information about an error, try `rustc --explain E0603`.
error: could not compile `weldmock`.

Caused by:
  process didn't exit successfully: `rustc --crate-name weldmock src\main.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -Cembed-bitcode=no -C debuginfo=2 -C metadata=07215c868661c321 --out-dir C:\BitBucket\Rust\weld-master\target\debug\deps -C incremental=C:\BitBucket\Rust\weld-master\target\debug\incremental -L dependency=C:\BitBucket\Rust\weld-master\target\debug\deps --extern bytes=C:\BitBucket\Rust\weld-master\target\debug\deps\libbytes-2548d93e1fba7e01.rlib --extern futures=C:\BitBucket\Rust\weld-master\target\debug\deps\libfutures-77d46f9522c81dae.rlib --extern futures_cpupool=C:\BitBucket\Rust\weld-master\target\debug\deps\libfutures_cpupool-8fec00508ae16a84.rlib --extern hyper=C:\BitBucket\Rust\weld-master\target\debug\deps\libhyper-810c394286b9e558.rlib --extern lazy_static=C:\BitBucket\Rust\weld-master\target\debug\deps\liblazy_static-3058c6f12d44e685.rlib --extern rand=C:\BitBucket\Rust\weld-master\target\debug\deps\librand-5588f3c0ef422b0e.rlib --extern serde=C:\BitBucket\Rust\weld-master\target\debug\deps\libserde-9fb117223d51cdf7.rlib --extern serde_derive=C:\BitBucket\Rust\weld-master\target\debug\deps\serde_derive-3345c08c9809f3ee.dll --extern serde_json=C:\BitBucket\Rust\weld-master\target\debug\deps\libserde_json-2386744b445deb8c.rlib --extern slog=C:\BitBucket\Rust\weld-master\target\debug\deps\libslog-27db374df41a8f6f.rlib --extern slog_async=C:\BitBucket\Rust\weld-master\target\debug\deps\libslog_async-90ae84865c8b2898.rlib --extern slog_term=C:\BitBucket\Rust\weld-master\target\debug\deps\libslog_term-6ff45e9e118bb74d.rlib --extern time=C:\BitBucket\Rust\weld-master\target\debug\deps\libtime-4d0067c55314a829.rlib` (exit code: 1)

Too much stringification

In main.rs

Some(path) => configuration.load(&path.to_string()),

the arg ends up passed to File::open, which takes a reference as an argument, so I think this could be simplified to just passing "path" to configuration.load. Similarly

configuration.load(&"weld.json".to_string());

why not just

configuration.load("weld.json") ?

fix error handling and return codes.

All of them will use predefined codes (200,201,404,412 etc. ). DB ops return types must be Result so errors could be usable at the RestService.

tests...

Since the dependencies are fixed and basic skeleton created it is the sweet spot for writing tests.

cascading support for all http methods

GET is working , post,put,delete must support cascading operations at all data types.
forex.
DELETE http://127.0.0.1:8080/owner or
DELETE http://127.0.0.1:8080/owner/name or
PUT http://127.0.0.1:8080/version

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.