Git Product home page Git Product logo

tino's People

Contributors

mk0y avatar panther99 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

tino's Issues

Introduce "root" option for responders

For responders like jsondb we will need "root" option since after simplifying handleUse function (#63) there's no way to determine if '/api' is custom path or a responder.

Example:

app.any(() => ({ path: "/api", use: jsondb(), root: true }));

This way it's enough to test paths with like .startsWith method.

Access with :params doesn't work

// http :8000/ping/12
const use = () => ({ resp: "pong" });
app.get(() => ({ path: "/ping/:id", use }));

Result: HTTP/1.1 404 Not Found

POST Method

POST method for jsondb responder.

Add new entity:

POST /api/laptops
{
  brand: "...",
  everything: "...",
  else: "...",
}

It should also create new entities which are not "plural" (in arrays), and besides objects also primitives in body.

POST /api
{
  note: {
    text: "...",
    date: "20-01-2021",
  }
}

Now it should be accessible on: GET /api/note

jsondb test coverage

In jsondb.js it's important to cover following(all) functions:

  • jsondb
  • buildResponseBody
  • handleJson (core)
  • buildResponse
  • try* HTTP method functions
  • tryProps
  • tryRestful
  • tryDirectLens
  • checkJsonDb
  • readJsonDb

dry-run option

Add dry option:

app.any(() => ({ path: "/api", use: jsondb(true) }));

Notice true as parameter to jsondb(). Definition of jsondb should change to something like:

const jsondb = (
  dry = false,
  process = processJsonOrContent,
  checkFile = checkJsonDb
) => ...

Tests should be updated accordingly (if any).

PATCH method

PATCH method for jsondb responder.

PATCH /api/laptops/1
{
  onlyThis:: "props",
}

PATCH should only work on objects. It updates only part of a single resource.

PATCH /api/laptops/1: patches an item in array of items
PATCH /api/laptop: patches an item

On success 200 is return with payload body.

Set content type for a request

Header should be set as for example: Accept: text/html (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept)

Controller API should look like:

const controller = () => ({ resp: "pong", status: 200, type: 'text/html' });
app.get(() => ({ path: "/ping", use: controller }));

If "type" is omitted it's set as "text/plain" but if http_server detects an object or array it should remain "application/json" - as it is currently working.

So "type" is optional like "status" and return type should now be like it is currently but with added "type" as optional: { resp, status?, type? }.

Preserve id on entity update

This mostly makes sense for PUT but should work for POST and PATCH too.

Existing entity:

{ id: 1, text: "str1" }

Request:

PUT /api/entity/1
{ text: "str2" }

Modified entity:

{ id: 1, text: "str2" }

Current behaviour:

{ text: "str2" }

POST method not working properly for a non-existing path

When you try to make a POST request for non-existing path, resource is not created in it's parent but in the root object.

For example:

POST /api/laptops/999
{
  "id": 999,
  "brand": "apple"
}

Will result in:

{
    "response": {
        "genres": [
            "comedy",
            "thriller",
            "drama"
        ],
        "laptops": [
            {
                "id": 123,
                "brand": "dell"
            },
            {
                "id": 2321,
                "brand": "lenovo"
            },
            {
                "id": 3311,
                "brand": "toshiba"
            }
        ],
        "color": {
            "dark": "blue",
            "light": "red"
        },
        "id": 999,
        "brand": "apple"
    }
}

e2e for all possible cases

We need to run e2e tests against possible endpoints.

Let's sum up what it can be:

JSON API:

  1. GET:
  • /api - whole json
  • /api/genres - list
  • /api/genres/0 - single item (with lenses)
  • /api/laptops - list all
  • /api/laptops/123 - by id
  • /api/laptops/9090909 - not found
  • /api/laptops/0 - by index (lenses)
  • /api/laptops?prop=name - filter by prop (200 success, empty array if no results)
  • /api/color - object
  • /api/color/dark - string
  • /api/color/absbdbd - not found
  1. POST: creates new record, always needs a payload (object, primitive)
  • /api - payload { name: value} create record at root level
  • /api/genres - payload string, but can be object
  • /api/genres/0 - bad request (status 422)
  • /api/laptops - { obj: name } create item
  • /api/laptops/123 - status 422
  1. PUT: create or replace an entity
  • /api - payload { name: value} create record at root level
  • /api/genres - payload string, but can be object
  • /api/genres/0 - any (obj|string|number|etc)
  • /api/laptops - { obj: name } create item
  • /api/laptops/123 - replace
  1. PATCH: update an entity
  • /api - payload { name: value} update record at root level
  • /api/genres - status 400
  • /api/genres/0 - status 400 (not an object)
  • /api/laptops - 400
  • /api/laptops/123 - update item
  1. DELETE: deletes an entity (by id or index)
  • /api - status 400
  • /api/genres/0 - success 200
  • /api/laptops - delete laptops completely
  • /api/laptops/123 - delete item, 200
  • /api/color - 200, delete color entity completely

Custom endpoints

  • app.any(() => ({ path: "/myapi", use: jsondb() })); should replicate /api endpoint
  • app.get(() => ({ path: "/myapi", use: () => ({ resp: "string", status: 201 }) })); custom responder with use:
  • app.get(() => ({ path: "/path", resp: "string" })); direct result, content-type "text/plain"
  • app.any(() => ({ path: "/path", resp: "string" })); ANY method, direct result, content-type "text/plain"
  • app.get(() => ({ path: "/path", resp: () => "string" })); same as above
  • app.get(() => ({ path: "/path", resp: async () => "string" })); same as above
  • app.get(() => ({ path: "/path", resp: { o: 1 } })); direct result, content-type "application/json"
  • app.post(() => ({ path: "/path", resp: "string" })); POST method, direct result, content-type "text/plain"
  • app.post(() => ({ path: "/path", resp: { o: 1 } })); POST method, direct result, content-type "application/json"
  • app.put(() => ({ path: "/path", resp: () => "string" })); direct result, content-type "text/plain"
  • app.patch(() => ({ path: "/path", resp: () => "string" })); direct result, content-type "text/plain"
  • app.delete(() => ({ path: "/path", resp: () => "string" })); direct result, content-type "text/plain"
  • app.delete(() => ({ path: "/path", resp: () => 200 })); status 200
  • app.not_found(() => ({ resp: () => "Oops" })); status 404, content "Oops", when none of the above is requested

dry-run

Any test above with dry=true shouldn't update db.json but return a result.

Any method except GET shouldn't return any payload on success, just 2xx is enough.

Allow passing multiple method handlers for the same path

Currently it's not possible to handle multiple HTTP request methods on the same path. For example:

app.get(() => ({ path: "/ping", resp: () => "pong" }));
app.delete(() => ({ path: "/ping", resp: () => "pong" }));

will add only delete method handler on the path ping.

Content type is not set sometimes

Try request: :8000/ping

When:

const use = () => ({ resp: "pong", status: 200 });
app.get(() => ({ path: "/ping", use  }));

Getting:

HTTP/1.1 200 OK
content-length: 4

But there is no content type.

Add returning data with the same type as a target resource on non-dry run

When dry run is off and user makes a request on /api/laptops route (or other route where the target is an array), the response should be:

{
  "response": []
}

In the same way, if user makes a request on /api/color route when dry run is off (or other route where the target is an object), the response should be:

{
  "response": {}
}

For primitive types it should be:

{
  "response": null
}

Rename json_server to tino

We'll rename this project to Tino to give name to something that's both HTTP server WITH fake JSON REST API for prototyping as an out of box responder.

Update db.json file

On each POST, PUT, PATCH or DELETE method, file json.db should be updated.

Tests should reflect this.

If there's dry run option set, don't save to the file but only output the result.

jsondb should return data only for GET method

PUT (only for update), PATCH, DELETE should only return 200/ok for successful operation.

On create it should return created resource - POST always, PUT only when created (not when updated).

PUT method

PUT method for jsondb responder.

PUT /api/laptops/1
{
  brand: "..."
  other: "props",
  ...
}

If the record doesn't exist create it, otherwise replace it.

Same as with POST method in #3 it should accept all possible values too.

[Bug] Delete by query params

DELETE :8000/api/laptops?brand=lenovo

Deletes all laptops. Should delete only ones which have "brand" set to "lenovo".

[Bug] POST method produces null

Making this request:

POST :8000/api/laptops
{ "brand": "lg" }

Adds null to the list:

"laptops": [
    {
      "id": 123,
      "brand": "dell"
    },
    {
      "id": 2321,
      "brand": "lenovo"
    },
    {
      "id": 3311,
      "brand": "toshiba"
    },
    null
  ],

Fix route being hit if it starts like the requested one

Currently, if you define a route like:

app.delete(() => ({
  path: "/path",
  use: () => ({ status: 201 }),
}));

It would be possible to hit it with a DELETE request to /pathf (notice how both are starting with the word path).

Add CLI option

Using CLI program should run as if it's set programatically.

deno run json_server.js --dry=true

Now, by default, we should have running server which supports CRUD operations on db.json file on /api route, same as defining manually:

app.any(() => ({ path: "/api", resp: jsondb() }));
  1. --dry-true means jsondb is called with dry=true option, jsondb(true)
  2. omitting --dry or setting --dry=false means just jsondb()

In first draft custom routes are defined manually like in repl.js file.

Rename to resp

// From:
app.get(() => ({ path: "/func", body: () => "return" }));
// To: 
app.get(() => ({ path: "/func", resp: () => "return" }));

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.