474 lines
12 KiB
Plaintext
474 lines
12 KiB
Plaintext
|
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Import libraries we need\n",
|
||
|
"import requests\n",
|
||
|
"import urllib.parse"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# You must run this cell, but you can ignore its contents.\n",
|
||
|
"import hashlib\n",
|
||
|
"\n",
|
||
|
"def ads_hash(ty):\n",
|
||
|
" \"\"\"Return a unique string for input\"\"\"\n",
|
||
|
" ty_str = str(ty).encode()\n",
|
||
|
" m = hashlib.sha256()\n",
|
||
|
" m.update(ty_str)\n",
|
||
|
" return m.hexdigest()[:10]"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"SWAPI_BASE='https://swapi.py4e.com/api/'\n",
|
||
|
"\n",
|
||
|
"def starwars_url(path):\n",
|
||
|
" '''return a URL to the Star Wars API using SWAPI_BASE\n",
|
||
|
" \n",
|
||
|
" For example, to get the URL for person with ID 10,\n",
|
||
|
" call:\n",
|
||
|
" \n",
|
||
|
" starwars_url('people/10/')\n",
|
||
|
" '''\n",
|
||
|
" return urllib.parse.urljoin(SWAPI_BASE,path)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"We need to be able to create an HTTP request to get a particular person from SWAPI. We are going to be making HTTP GET requests using the URL to request the information we want. So, we need to create a String with the appropriate request. \n",
|
||
|
"\n",
|
||
|
"### Q1 Define a function which will take an integer as an argument and return a string, which is the URL to get that particular person from the SWAPI. Call your function `get_person_url`.\n",
|
||
|
"\n",
|
||
|
"For example for person 42, this function should return something like: `\"https://swapi.dev/api/people/42/\"`. However, the URL should be made with the `starwars_url()` function so that it starts with the value `SWAPI_BASE` (and not necessarily `https://swapi.dev/api`). This is useful in case the website changes location or in case we decide to start hosting our own copy of the website at a different URL."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "123cd45642aa84465efcf20b41a4bcd5",
|
||
|
"grade": false,
|
||
|
"grade_id": "cell-496b12c0d3e2489f",
|
||
|
"locked": false,
|
||
|
"schema_version": 3,
|
||
|
"solution": true,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# YOUR CODE HERE\n",
|
||
|
"raise NotImplementedError()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"editable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "9c455b07be482a944e0dd36f29b4b8c1",
|
||
|
"grade": true,
|
||
|
"grade_id": "cell-b3a7ebab227918e4",
|
||
|
"locked": true,
|
||
|
"points": 1,
|
||
|
"schema_version": 3,
|
||
|
"solution": false,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# This checks that the above worked\n",
|
||
|
"person_10_url = get_person_url(10)\n",
|
||
|
"assert(type(person_10_url)==str)\n",
|
||
|
"assert(person_10_url.startswith(SWAPI_BASE))\n",
|
||
|
"assert(person_10_url.endswith('people/10') or person_10_url.endswith('people/10/'))"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Now, let's use the Python `requests` library to make an HTTP GET call to this URL. View its documentation at https://docs.python-requests.org/en/latest/.\n",
|
||
|
"\n",
|
||
|
"### Q2 Using your `get_person_url()` function, create a variable called `person_url` for person 10. Now, assign the result of `requests.get(person_url)` to a variable called `response`."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "0afcfa14509b7c7ef2df50711ba2588f",
|
||
|
"grade": false,
|
||
|
"grade_id": "cell-65e02d72fd413542",
|
||
|
"locked": false,
|
||
|
"schema_version": 3,
|
||
|
"solution": true,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# YOUR CODE HERE\n",
|
||
|
"raise NotImplementedError()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"editable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "09bf79ea731a2c2fc7b762a7ab6f03fe",
|
||
|
"grade": true,
|
||
|
"grade_id": "cell-cbc105eff3987aa9",
|
||
|
"locked": true,
|
||
|
"points": 1,
|
||
|
"schema_version": 3,
|
||
|
"solution": false,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# This checks that the above worked\n",
|
||
|
"assert ads_hash(response.json()['name'])=='6e84377ee7'"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Now let's wrap this up in a function which takes a person ID number and returns a dictionary for that person using the `response.json()` method from `requests`.\n",
|
||
|
"\n",
|
||
|
"### Q3 Make a function called `get_person` which takes an integer as an argument and returns a dict with the result from the SWAPI"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "cde15d2b38e6db3c5da774b360ee97fc",
|
||
|
"grade": false,
|
||
|
"grade_id": "cell-11010cba389895bd",
|
||
|
"locked": false,
|
||
|
"schema_version": 3,
|
||
|
"solution": true,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# YOUR CODE HERE\n",
|
||
|
"raise NotImplementedError()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"editable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "fe1396d2cb793b6bf338b633a7f4ff07",
|
||
|
"grade": true,
|
||
|
"grade_id": "cell-9c11e54ba69189a0",
|
||
|
"locked": true,
|
||
|
"points": 1,
|
||
|
"schema_version": 3,
|
||
|
"solution": false,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# This checks that the above worked\n",
|
||
|
"assert ads_hash(get_person(1)['name'])=='9d00804504'"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## HTTP POST requests\n",
|
||
|
"\n",
|
||
|
"Up to now, we have been using HTTP GET requests. These are what your browser does when you go to a webpage and are good for getting information.\n",
|
||
|
"\n",
|
||
|
"Sometimes, however, we want to upload more complicated data to another program. This is often done with the HTTP POST request.\n",
|
||
|
"\n",
|
||
|
"Here we are going to POST data to a server which will add a value to our input."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"ADDER_URL = 'http://http-demo-server.strawlab.org/'\n",
|
||
|
"response = requests.post(ADDER_URL+'add_to_value', json={'value':100})"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Any status code other than 200 is an error\n",
|
||
|
"response.status_code"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"response.text"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"response.json()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"### Q4 What is the value added the the input by the HTTP server? Put your answer in the variable `added`."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "b776f1be5127a33abdd6f64bdb51ae5c",
|
||
|
"grade": false,
|
||
|
"grade_id": "cell-6f8a3c2b5f23135e",
|
||
|
"locked": false,
|
||
|
"schema_version": 3,
|
||
|
"solution": true,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# YOUR CODE HERE\n",
|
||
|
"raise NotImplementedError()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"editable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "856250764f979ca97e3e124ffd37a325",
|
||
|
"grade": true,
|
||
|
"grade_id": "cell-60ba73a7486b8988",
|
||
|
"locked": true,
|
||
|
"points": 1,
|
||
|
"schema_version": 3,
|
||
|
"solution": false,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# This checks that the above worked\n",
|
||
|
"assert ads_hash(added)=='73475cb40a'"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"### Q5 There is another path on our server called `mystery`. It works similarly to `add_to_value`. What is the JSON `value` returned by this HTTP endpoint when called with an input value of 100? Put your answer in the variable `mystery100`."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "4bf4a4c1015892f6e367f9981a12c19b",
|
||
|
"grade": false,
|
||
|
"grade_id": "cell-51d14040f23943ad",
|
||
|
"locked": false,
|
||
|
"schema_version": 3,
|
||
|
"solution": true,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# YOUR CODE HERE\n",
|
||
|
"raise NotImplementedError()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"editable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "c4c876385b03a639a16db8fc3e80e295",
|
||
|
"grade": true,
|
||
|
"grade_id": "cell-3392fa03f78e9c65",
|
||
|
"locked": true,
|
||
|
"points": 1,
|
||
|
"schema_version": 3,
|
||
|
"solution": false,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# This checks that the above worked\n",
|
||
|
"assert ads_hash(mystery100)=='26d228663f'"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"### Q6 Play around with this `mystery` until you think you understand what it is doing. Now make a function called `myfunc` which takes a single integer argument and returns an integer which should do the same thing as the mystery HTTP endpoint."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "fdcba7ad40518f19c8101cb09239198f",
|
||
|
"grade": false,
|
||
|
"grade_id": "cell-cc8f1c957dc44cd2",
|
||
|
"locked": false,
|
||
|
"schema_version": 3,
|
||
|
"solution": true,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# YOUR CODE HERE\n",
|
||
|
"raise NotImplementedError()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"deletable": false,
|
||
|
"editable": false,
|
||
|
"nbgrader": {
|
||
|
"cell_type": "code",
|
||
|
"checksum": "a1a1d95d00521db5416d1a53b6f978b9",
|
||
|
"grade": true,
|
||
|
"grade_id": "cell-b48cf735571f569b",
|
||
|
"locked": true,
|
||
|
"points": 1,
|
||
|
"schema_version": 3,
|
||
|
"solution": false,
|
||
|
"task": false
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# This checks that the above worked\n",
|
||
|
"assert ads_hash(type(myfunc))=='ac75372cfc' \n",
|
||
|
"assert ads_hash(myfunc(3))=='6b51d431df'\n",
|
||
|
"assert ads_hash(myfunc(5))=='f5ca38f748'"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"# What have we learned here?\n",
|
||
|
"\n",
|
||
|
"HTTP is the \"language\" (protocol, to be technically correct) that your web browser uses to get webpages and images on the internet. More than that, it is also a useful language for computer programs to talk to each other on the internet.\n",
|
||
|
"\n",
|
||
|
"(HTTPS is just a secure version of HTTP. This means it is encrypted and there is a cryptographic \"chain of trust\" to the owner of the domain name.)\n",
|
||
|
"\n",
|
||
|
"GET requests typically just get a certain resource.\n",
|
||
|
"\n",
|
||
|
"POST requests often send more data to the server. The server then does something with this data.\n",
|
||
|
"\n",
|
||
|
"There are other HTTP request types, but GET and POST are the dominant ones.\n",
|
||
|
"\n",
|
||
|
"There are zillions of data sources on the internet that you can access with HTTP."
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"metadata": {
|
||
|
"kernelspec": {
|
||
|
"display_name": "Python 3 (ipykernel)",
|
||
|
"language": "python",
|
||
|
"name": "python3"
|
||
|
},
|
||
|
"language_info": {
|
||
|
"codemirror_mode": {
|
||
|
"name": "ipython",
|
||
|
"version": 3
|
||
|
},
|
||
|
"file_extension": ".py",
|
||
|
"mimetype": "text/x-python",
|
||
|
"name": "python",
|
||
|
"nbconvert_exporter": "python",
|
||
|
"pygments_lexer": "ipython3",
|
||
|
"version": "3.11.7"
|
||
|
}
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 4
|
||
|
}
|