Added style #15. Does this clarify REST?
This commit is contained in:
35
15-restful/README.md
Normal file
35
15-restful/README.md
Normal file
@@ -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
|
||||||
|
|
||||||
108
15-restful/tf-15.py
Normal file
108
15-restful/tf-15.py
Normal file
@@ -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)
|
||||||
Reference in New Issue
Block a user