Giter Club home page Giter Club logo

presto's Introduction

presto

Presto backend API coding challenge

Table of Contents

Task

Utilizing your language of choice, design a RESTful web service API call that will return a list of menu items for a specific restaurant.

Specifics

For this API call, the front end will target path /restaurant/:restaurantId/item.

public Observable<Response> execute(Request request) {
URL url = new URL("https://api.presto.com/restaurant/1/item");
HttpURLConnection con = url.openConnection();
}

The expected response will be parsed directly from JSON to a list of Item objects.

execute(request).subscribe(response -> {
Type listType = new TypeToken<List<Item>>(){}.getType();
List<Item> items = new Gson().fromJson(response, listType); });

Requirements

This challenge is centered around the concept of communicating throughout the stack from the backend, so each part of that communication stack is required:

  1. Handle the request from the front end
  2. Connect to and query from a Postgres database instance
  3. Send the response to the front end

The data model structure is up to you, it’s assumed that the frontend will mimic your object layout for seamless parsing. The only requirement is that the Item object must contain a list of modifiers (ex. Side item, Topping, Sauce). Hint - modifiers can also have modifiers (think dressing choices for side salad).

Scalability is paramount. The code you build should not end up being a bottleneck down the road (will this have to be rebuilt when it’s being hit 100x as frequently?).

Design

Architecture

  • Framework: I am using JavaScript and Node, simply because I am very familiar with them.
  • API Design: Swagger Editor to generate the API contract and swagger-codegen to generate the node server using express.
  • Scalability: Node is commonly used for designing production ready scalable and concurrent backend systems. If you are writing a backend using javascript (I am), then node is your huckleberry.
  • Database: Postgres, because it was specified in the challenge.
  • Database Connectivity: Using Sequelize, which is the most popular (by download statistics) SQL ORM software package for node:
    • Sequelize The Sequelize library is an ORM (Object-Relational-Mapper) which provides easy access to MySQL, MariaDB, SQLite or PostgreSQL databases by mapping database entries to objects and vice versa.
    • List of most popular ORM packages according to npmjs
    • Comparison of mongoose vs sequalize over last 6 months
  • Security: There is none, due to the nature of the challenge.
  • Queries: Will use a Common Table Expression (CTE) query through sequelize to keep this scalable. Node will ensure this remains scalable through asyncronous promises (meaning it will not block other requests while the DB handles this query for as long as it takes). Queries from the postgres command line using the sample data are recorded here.

Trade Offs

  • I chose not to use python and django because I am unfamiliar with them and preferred to complete this challenge with tools I am proficient with.
  • Using Sequelize over Mongoose because challenge calls for it. Trade-off here is lilliputian battle of SQL vs NoSQL.
  • No security, never do this, ever. period.
  • I stuck with the naming convention used in the coding challenge, but I am not certain that matches the database schema well.
  • I used three tables to split up the data. It makes the query more complicated (needing Joins), but I think it is more extensible.

Postgres

Configuration

Configure the connection to your postgres server by modifying modules/restaurant/server/config/database.json. The defaults are:

  "development": {
    "username": "presto",
    "password": "presto",
    "database": "presto",
    "host": "192.168.56.102",
    "port": "5432",
    "dialect": "postgres"
  },

Starting Fresh with Postgres

  • Create a presto user and presto database, or sh modules/restaurant/server/scripts/database/postgres.sh
postgres@localhost:~$ createuser --echo --pwprompt --createdb --no-createrole --no-superuser presto
postgres@localhost:~$ createdb presto

Starting Fresh with Sequelize

This will create new models, this should be unnecessary as files are tracked in git.

cd modules/restaurant/server/scripts/database
sh ./sequelize-initialize-environment.sh
sh ./sequelize-create-models.sh

Seeding database

This will drop the current database and re-seed it from a known state

cd modules/restaurant/server/scripts/database
sh ./sequelize-seed-database.sh

Server

The server stub was generated by the swagger-codegen project.

Running the server

To run the server for the first time, run:

cd modules/restaurant/server
npm start

To run just the server, run:

node index.js

To view the Swagger UI interface:

open http://localhost:8080/docs

This project leverages the mega-awesome swagger-tools middleware which does most all the work.

Client

Read the Client instructions here. Here is a shortcut:

cd modules/restaurant/client
npm install

and to test:

npm test

Database Schema

I am using three tables to track Restaurants, Items, and Menus:

  • Restaurant - List of available restaurants, restaurantID in API.
  • Items - Items available at a restaurant, associated with a Restaurant.
  • Menu - Table holding relationship of items to each other. An item where Modifies is NULL is a top-level item. This table allows for a hierarchical relationship. Care must be taken (and code introduced) to prevent cyclic dependencies. Ultimately this relationship table defines the response to the API challenge.

Restaurant Table

RestaurantID Name
(pk) int string

Item Table - Associated with Restaurant Table

ItemID RestaurantID Name Description
(pk) int (fk) RestaurantID string string

Menu Table

MenuID itemID RestaurantID Modifies Description
(pk) int (fk) ItemID (fk) RestaurantID (fk) itemID string

Future Work

These are things I would do if I had more time:

  • Use UUIDs instead of incrementing ints for primary keys
  • Default string lengths (255) used for all fields, would make them reasonable
  • Cannot stress implement proper security enough - https, SSL connection to DB, secure DB, API keys, API authentication, etc.
  • Complete CRUD API. Use that to seed database for test environment (database provisioning/migration still done with npm install).
  • Performance tests:
    • Multiple restaurants
    • X simultaneous clients
    • Y items (with modifiers)
      • random item generator
      • connection reliability (intermittent connections)
      • low bandwidth connectivity (e.g. 1 Mbps down, 0.04 Mbps up)
    • Resource graphcs under load testing
      • Memory, CPU usage
      • Perf statistics
      • SQL call duration
      • gprof
      • O(N) estimation
  • Move database documentation from here to a schema definition file to avoid decoupling
  • Protection against cyclic graphs, e.g.:

Menu Table: Check for cyclic association in table

(Note - Example only, not Schema accurate)

ItemID Modifies Note Problem
1 NULL Top level item
2 1 Green Salad as side to burger
3 2 Blue Cheese Dressing for salad
4 3 Extra blue cheese Cyclic association
3 4 Blue Cheese Dressing for blue cheese Cyclic association
4 4 Blue Cheese for blue cheese Cyclic association
  • Refactor CTE code to use native sequelize functionality, there seem to be some other modules that do this better.
  • Refactor tree building code in API to be a generic graph structure builder, this would be a more reusable component. I implemented a graph search algorithm, should optimize if more time.

License

Licensed under the Unlicense.

Acknowledgements

presto's People

Contributors

markhary avatar

Watchers

James Cloos 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.