From f9ae20233d7829dc5a2fe55e797b014245609b4d Mon Sep 17 00:00:00 2001 From: Crista Lopes Date: Mon, 23 Sep 2013 20:35:59 -0700 Subject: [PATCH] Added style #15. Does this clarify REST? --- 15-restful/README.md | 35 ++++++++++++++ 15-restful/tf-15.py | 108 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 15-restful/README.md create mode 100644 15-restful/tf-15.py diff --git a/15-restful/README.md b/15-restful/README.md new file mode 100644 index 0000000..569654b --- /dev/null +++ b/15-restful/README.md @@ -0,0 +1,35 @@ +Style #15 +============================== + +REST = REpresentational State Transfer (http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm) + +REST is a style for network-based interactive applications that +underlies the Web. The example here doesn't go over the network, but +preserves the main contraints of REST, which are: + +- Interactive: end-to-end between an active agent (e.g. a person) and a backend + +- Separation between Client (user interface) and Server (data storage) + +- Statelessness, as in client--stateless-server: every request from + client to server must contain all the information necessary for the + server to serve the request. The server cannot store + context of the interaction. Session state is on the client. + +- Uniform interface: resources that are created and retrieved, + resource identifiers and hypermedia representation that is the + engine of application state + +Additionally, the networked style has the following contraints, not shown here: + +- Cache + +- Layered system + +- Code-on-demans + +Possible names: + +- RESTful +- Stateless Ping-Pong + diff --git a/15-restful/tf-15.py b/15-restful/tf-15.py new file mode 100644 index 0000000..0adc9a4 --- /dev/null +++ b/15-restful/tf-15.py @@ -0,0 +1,108 @@ +import re, string, sys + +with open("../stop_words.txt") as f: + stops = set(f.read().split(",") + list(string.ascii_lowercase)) +# The "database" +data = {} + +# Internal functions of the "server"-side application +def error_state(): + return "Something wrong", ["get", "default", None] + +# The "server"-side application handlers +def quit_handler(args): + sys.exit("Goodbye cruel world...") + +def default_get_handler(args): + rep = "What would you like to do?" + rep += "\n1 - Quit" + "\n2 - Upload file" + links = {"1" : ["post", "execution", None], "2" : ["get", "file_form", None]} + return rep, links + +def upload_get_handler(args): + return "Name of file to upload?", ["post", "file"] + +def upload_post_handler(args): + def create_data(filename): + if filename in data: + return + word_freqs = {} + print "Trying to open " + filename + with open(filename) as f: + for w in [x.lower() for x in re.split("[^a-zA-Z]+", f.read()) if len(x) > 0 and x.lower() not in stops]: + word_freqs[w] = word_freqs.get(w, 0) + 1 + word_freqsl = word_freqs.items() + word_freqsl.sort(lambda x, y: cmp(y[1], x[1])) + data[filename] = word_freqsl + + if args == None: + return error_state() + + filename = args[0] + try: + create_data(filename) + except: + return error_state() + + return word_get_handler([filename, 0]) + +def word_get_handler(args): + def get_word(filename, word_index): + if word_index < len(data[filename]): + return data[filename][word_index] + else: + return ("no more words", 0) + + filename = args[0]; word_index = args[1] + word_info = get_word(filename, word_index) + rep = '\n#{0}: {1} - {2}'.format(word_index+1, word_info[0], word_info[1]) + rep += "\n\nWhat would you like to do next?" + rep += "\n1 - Quit" + "\n2 - Upload file" + rep += "\n3 - See next most-frequently occurring word" + links = {"1" : ["post", "execution", None], + "2" : ["get", "file_form", None], + "3" : ["get", "word", [filename, word_index+1]]} + return rep, links + +# Handler registration +handlers = {"post_execution" : quit_handler, + "get_default" : default_get_handler, + "get_file_form" : upload_get_handler, + "post_file" : upload_post_handler, + "get_word" : word_get_handler } + +# The "server" core +def handle_request(verb, uri, args): + def handler_key(verb, uri): + return verb + "_" + uri + + if handler_key(verb, uri) in handlers: + return handlers[handler_key(verb, uri)](args) + else: + return handlers[handler_key("get", "default")](args) + +# A very simple client "browser" +def render_and_get_input(state_representation, links): + print state_representation + if type(links) is dict: # many possible next states + input = sys.stdin.readline().strip() + if input in links: + return links[input] + else: + return ["get", "default", None] + elif type(links) is list: # only one possible next state + if links[0] == "post": # get "form" data + input = sys.stdin.readline().strip() + links.append([input]) # add the data at the end + return links + else: # get action, don't get user input + return links + else: + return ["get", "default", None] + +request = ["get", "default", None] +while True: + # "server"-side computation + state_representation, links = handle_request(*request) + # "client"-side computation + request = render_and_get_input(state_representation, links)