Git Product home page Git Product logo

widgets's Introduction

Widget Factory

The REST API you never needed, to keep track of widgets you never wanted.

It's designed to run from a directory on a Linux machine, but just might work on other types of systems. To use it, first set up a Python virtual environment for it:

$ git clone https://github.com/eswald/widgets.git
Cloning into 'widgets'...
remote: Enumerating objects: 68, done.
remote: Counting objects: 100% (68/68), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 68 (delta 39), reused 67 (delta 38), pack-reused 0
Unpacking objects: 100% (68/68), done.
$ cd widgets
$ python3 -m venv .env
$ . .env/bin/activate
$ pip install -U pip
Collecting pip
  ...
Successfully installed pip-21.2.4
$ pip install -r requirements.txt -c package-constraints.txt
Collecting aiosqlite
  ...
Installing collected packages: zipp, typing-extensions, importlib-metadata, tornado, click, aiosqlite
Successfully installed aiosqlite-0.17.0 click-8.0.1 importlib-metadata-4.7.1 tornado-6.1 typing-extensions-3.10.0.0 zipp-3.5.0

Your output will vary, of course. With that in place, run the Tornado web server:

$ python application.py
Listening...
Checking migrations: 0 / 5 ...
Running migration create_accounts_table...
Running migration create_tokens_table...
Running migration create_widgets_table...
Running migration soft_delete_widgets...
Running migration create_alphabets_table...
Migrations complete.

Those migration lines mean that it has set up a brand-new SQLite3 database with empty tables. By default, that will use a file named database.sqlite in the current directory, but you can change it with the --database command-line option.

By default, the server listens on port 8888. If you already have something running on that port, you can use the --port option to select a new one.

The server will run until it gets interrupted, such as with Ctrl-C. While it's running, you can make HTTP requests to it. There are many ways to do so, but the following commands will use HTTPie in a separate command terminal:

$ pip install httpie
Collecting httpie
  ...
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests, PySocks, requests-toolbelt, Pygments, httpie
Successfully installed PySocks-1.7.1 Pygments-2.10.0 certifi-2021.5.30 charset-normalizer-2.0.4 httpie-2.4.0 idna-3.2 requests-2.26.0 requests-toolbelt-0.9.1 urllib3-1.26.6
$ http localhost:8888/
HTTP/1.1 401 Unauthorized
Content-Length: 27
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:12:17 GMT
Server: TornadoServer/6.1

{
    "error": "Not Authorized"
}

Right. You wouldn't want just anyone meddling with your widgets, so this application requires an authorization token. Create one by asking it to create a new account for you:

$ http POST localhost:8888/ "name=<Your account name here>"
HTTP/1.1 200 OK
Content-Length: 79
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:12:59 GMT
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "token": "05367170-a27b-4559-ac97-5fa6e817ec75"
}

In case you're using another way to test the API, that name= parameter tells HTTPie to send a JSON request with {"name": "<Your account name here>"} in the body.

Now that you have an authorization token, you can use it to make requests. For example, getting your account information:

$ http localhost:8888/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75"
HTTP/1.1 200 OK
Content-Length: 170
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:18:55 GMT
Etag: "c0e047b4e5cee75b353e2a02b2d7b80d2524e85b"
Server: TornadoServer/6.1

{
    "account": [
        {
            "created": "2021-08-29 14:12:59.726177+00:00",
            "id": "account-bjzwrdg",
            "name": "<Your account name here>",
            "updated": "2021-08-29 14:12:59.726177+00:00"
        }
    ]
}

Or the widgets in your account:

$ http localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75"
HTTP/1.1 200 OK
Content-Length: 45
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:19:37 GMT
Etag: "70e814764369cc4b5750dcf92932778a16577a55"
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widgets": []
}

But, of course, there aren't any. Yet. Use POST requests to make them:

$ http POST localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75" "name=Frame" "parts:=1"
HTTP/1.1 200 OK
Content-Length: 210
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:20:40 GMT
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widget": {
        "created": "2021-08-29 14:20:40.848936+00:00",
        "description": null,
        "id": "widget-tdvswpg",
        "name": "Frame",
        "parts": 1,
        "updated": "2021-08-29 14:20:40.848936+00:00"
    }
}

That := in the parts field tells http to send that field as an integer, instead of a string. Essentially, it sends {"name": "Frame", "parts": 1} to the server, barring variations in field order and whitespace. Widget creation also accepts an optional description field:

$ http POST localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75" "name=Front Brake System" "parts:=10" "description=Lever, cables, brake pads, and mountings"
HTTP/1.1 200 OK
Content-Length: 262
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:26:13 GMT
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widget": {
        "created": "2021-08-29 14:26:13.654168+00:00",
        "description": "Lever, cables, brake pads, and mountings",
        "id": "widget-rmzvqjw",
        "name": "Front Brake System",
        "parts": 10,
        "updated": "2021-08-29 14:26:13.654168+00:00"
    }
}
$ http POST localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75" "name=Handlebar Assembly" "parts:=14" "description=Including the mount point for the frame."
HTTP/1.1 200 OK
Content-Length: 262
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:26:41 GMT
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widget": {
        "created": "2021-08-29 14:26:41.721508+00:00",
        "description": "Including the mount point for the frame.",
        "id": "widget-ppgtxnz",
        "name": "Handlebar Assembly",
        "parts": 14,
        "updated": "2021-08-29 14:26:41.721508+00:00"
    }
}

Listing the widgets will now give us a bit more data:

$ http localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75"
HTTP/1.1 200 OK
Content-Length: 657
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:28:43 GMT
Etag: "bdd6baad435f84701169524d3d87cb76817509c2"
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widgets": [
        {
            "created": "2021-08-29 14:20:40.848936+00:00",
            "description": null,
            "id": "widget-tdvswpg",
            "name": "Frame",
            "parts": 1,
            "updated": "2021-08-29 14:20:40.848936+00:00"
        },
        {
            "created": "2021-08-29 14:26:13.654168+00:00",
            "description": "Lever, cables, brake pads, and mountings",
            "id": "widget-rmzvqjw",
            "name": "Front Brake System",
            "parts": 10,
            "updated": "2021-08-29 14:26:13.654168+00:00"
        },
        {
            "created": "2021-08-29 14:26:41.721508+00:00",
            "description": "Including the mount point for the frame.",
            "id": "widget-ppgtxnz",
            "name": "Handlebar Assembly",
            "parts": 14,
            "updated": "2021-08-29 14:26:41.721508+00:00"
        }
    ]
}

Come to think of it, that part count for the brake system seems a little low. Lets add all the nuts, bolts, washers, and springs to it, with the PUT API:

$ http PUT localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75" id=widget-rmzvqjw parts:=24
HTTP/1.1 200 OK
Content-Length: 262
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:34:47 GMT
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widget": {
        "created": "2021-08-29 14:26:13.654168+00:00",
        "description": "Lever, cables, brake pads, and mountings",
        "id": "widget-rmzvqjw",
        "name": "Front Brake System",
        "parts": 24,
        "updated": "2021-08-29 14:34:47.067746+00:00"
    }
}

Or perhaps we want a trike instead, which doesn't need a handlebar assembly. So let's go ahead and delete that:

$ http DELETE localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75" id=widget-rmzvqjw
HTTP/1.1 200 OK
Content-Length: 309
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:38:01 GMT
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widget": {
        "created": "2021-08-29 14:26:13.654168+00:00",
        "deleted": "2021-08-29 14:38:01.306165+00:00",
        "description": "Lever, cables, brake pads, and mountings",
        "id": "widget-rmzvqjw",
        "name": "Front Brake System",
        "parts": 24,
        "updated": "2021-08-29 14:34:47.067746+00:00"
    }
}

And we see that it's no longer in the list:

$ http localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75"
HTTP/1.1 200 OK
Content-Length: 435
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:38:27 GMT
Etag: "07ec7a8f0b74dc98c2620998c822a61d03a22077"
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widgets": [
        {
            "created": "2021-08-29 14:20:40.848936+00:00",
            "description": null,
            "id": "widget-tdvswpg",
            "name": "Frame",
            "parts": 1,
            "updated": "2021-08-29 14:20:40.848936+00:00"
        },
        {
            "created": "2021-08-29 14:26:41.721508+00:00",
            "description": "Including the mount point for the frame.",
            "id": "widget-ppgtxnz",
            "name": "Handlebar Assembly",
            "parts": 14,
            "updated": "2021-08-29 14:26:41.721508+00:00"
        }
    ]
}

Wait, that wasn't the handlebar assembly; that was the brakes! Quick, undo before you forget the id, and delete the right record:

$ http PATCH localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75" id=widget-rmzvqjw
HTTP/1.1 200 OK
Content-Length: 279
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:38:55 GMT
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widget": {
        "created": "2021-08-29 14:26:13.654168+00:00",
        "deleted": null,
        "description": "Lever, cables, brake pads, and mountings",
        "id": "widget-rmzvqjw",
        "name": "Front Brake System",
        "parts": 24,
        "updated": "2021-08-29 14:38:55.346884+00:00"
    }
}
$ http DELETE localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75" id=widget-ppgtxnz
HTTP/1.1 200 OK
Content-Length: 309
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:39:17 GMT
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widget": {
        "created": "2021-08-29 14:26:41.721508+00:00",
        "deleted": "2021-08-29 14:39:17.845582+00:00",
        "description": "Including the mount point for the frame.",
        "id": "widget-ppgtxnz",
        "name": "Handlebar Assembly",
        "parts": 14,
        "updated": "2021-08-29 14:26:41.721508+00:00"
    }
}

So how, you might ask, did we manage to restore a deleted record? By cheating, in a way; it was never really deleted, just marked as hidden from the API methods. This can be helpful when going over old logs, or tracking down bugs, particularly since SQLite has a habit of re-using deleted id numbers in certain situations.

Speaking of hiding, we can verify that other accounts don't see our widgets by creating a new account and using its auth token:

$ http POST localhost:8888/ name=Spyware
HTTP/1.1 200 OK
Content-Length: 79
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:41:58 GMT
Server: TornadoServer/6.1

{
    "account": "account-nvfzmpr",
    "token": "b439369c-31a7-4a32-bb87-5074601dfdec"
}
$ http GET localhost:8888/widgets/ "Authorization:Bearer b439369c-31a7-4a32-bb87-5074601dfdec"
HTTP/1.1 200 OK
Content-Length: 45
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:43:11 GMT
Etag: "88534c499ede97d713ba9cc8d21d036ca4c3bcf2"
Server: TornadoServer/6.1

{
    "account": "account-nvfzmpr",
    "widgets": []
}

But using the original auth token will still bring up the widgets we've created:

$ http localhost:8888/widgets/ "Authorization:Bearer 05367170-a27b-4559-ac97-5fa6e817ec75"
HTTP/1.1 200 OK
Content-Length: 435
Content-Type: application/json; charset=UTF-8
Date: Sun, 29 Aug 2021 14:44:33 GMT
Etag: "b3e92615d2fa1b3aa77638d8e5a9300e1de67e09"
Server: TornadoServer/6.1

{
    "account": "account-bjzwrdg",
    "widgets": [
        {
            "created": "2021-08-29 14:20:40.848936+00:00",
            "description": null,
            "id": "widget-tdvswpg",
            "name": "Frame",
            "parts": 1,
            "updated": "2021-08-29 14:20:40.848936+00:00"
        },
        {
            "created": "2021-08-29 14:26:13.654168+00:00",
            "description": "Lever, cables, brake pads, and mountings",
            "id": "widget-rmzvqjw",
            "name": "Front Brake System",
            "parts": 24,
            "updated": "2021-08-29 14:38:55.346884+00:00"
        }
    ]
}

widgets's People

Contributors

eswald avatar

Watchers

 avatar  avatar

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.