Termipankki
  1. A
    1. API Blueprint
    2. Addressability
    3. Ajax
    4. Anonymous Function
    5. App Context
  2. B
    1. Blueprint
    2. Business Logic
  3. C
    1. CORS
    2. Callback
    3. Client
    4. Column
    5. Column Attribute
    6. Connectedness
  4. D
    1. DOM
    2. Database Schema
  5. E
    1. Element
  6. F
    1. Fixture
    2. Flask App
    3. Foreign Key
  7. G
    1. Generic Client
  8. H
    1. HTTP Method
    2. HTTP Request
    3. Header
    4. Host Part
    5. Hypermedia
  9. I
    1. Instance Folder
  10. J
    1. JSON
    2. JSON Schema
  11. L
    1. Link Relation
  12. M
    1. MIME Type
    2. Migration
    3. Model Class
  13. O
    1. ORM
  14. P
    1. Primary Key
    2. Profile
  15. Q
    1. Query
    2. Query Parameter
  16. R
    1. Regular Expression
    2. Request
    3. Request Body
    4. Request Object
    5. Resource
    6. Resource Class
    7. Response
    8. Response Body
    9. Response Object
    10. Rollback
    11. Routing
    12. Route
      Routing
    13. Row
  17. S
    1. SQL
    2. Static Content
  18. T
    1. Table
    2. Test Setup
    3. Test Teardown
  19. U
    1. URI
    2. URL Template
    3. Unique Constraint
  20. V
    1. View Function
  21. W
    1. Web API
Ratkaistu: / tehtävää

Testing Flask Applications part 2

This page is a sequel to part 1 where we tested Flask applications manually and did some simple unit tests for
model classes
. This time we're going to do more "proper" testing. The focus is on API testing - ensuring that our API actually does what it promises. Just like in API implementation, some kind of strategy is crucial to stay sane. Otherwise there will be just endless amounts of copypaste code that is difficult to manage.

Resource Testing with Pytest

Preliminary Preparations

You can grab the single file version of the sensor management API from below.
sensorhub.py
We're going to implement another test file called resource_test.py. If you are using the the more elaborate project structure this file will be pretty similar and there are no complications because we're properly creating a new Flask app object with every test case. However if you are using single file and plan on running these new tests in addition to the database tests we implemented previously, you need to insert one line of code into the db_handle
fixture
after the yield line:
app.db.session.remove()
Because we're not actually creating the Flask app anew every time, for some reason the database session persists between test modules even though it doesn't persist between test cases in the database test module. Note that the database tests actually don't fully pass because of a change in the models. If you want to fix this problem, feel free to do so.

New Fix(ture)

Our fixture should be changed to one that yields a Flask test client. The new fixture looks like this:
# based on http://flask.pocoo.org/docs/1.0/testing/
# we don't need a client for database testing, just the db handle
@pytest.fixture
def client():
    db_fd, db_fname = tempfile.mkstemp()
    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + db_fname
    app.config["TESTING"] = True

    db.create_all()
    _populate_db()

    yield app.test_client()

    db.session.remove()
    os.close(db_fd)
    os.unlink(db_fname)
In order to properly test an API, there usually needs to be some data in the database for GET, PUT and DELETE requests to have something to work on. Our new fixture calls the yet-to-be-defined _populate_db function in order to achieve this. This function is in fact quite simple because so far we've only implemented the sensor
resources
. Therefore we only need sensors. Let's make three:
def _populate_db():
    for i in range(1, 4):
        s = Sensor(
            name="test-sensor-{}".format(i),
            model="testsensor"
        )
        db.session.add(s)
    db.session.commit()
Basically you can use the code you used for creating instances of each
model class
in database testing for this purpose, at least as a basis (just remove the asserts...) We're prefixing this function and its ilk with a single underscore to softly hint that these are the test module's internal tools.

Basic Testing

View and
resource
testing in Flask is generally done with the Flask test client which we introduced in the previous testing material. We already modified the fixture to provide this client, and its use is rather straightforward. We also recommend grouping tests into classes, one test class per
resource class
, mostly to get get some organization into the code with the added bonus of defining some constants as class attributes (e.g. the resource
URI
). Pytest's discovery automatically creates instances of these classes and calls any methods that start or end with test.
For basic unit testing, we want our tests to cover all nooks and crannies in the resource class methods thus ensuring that all lines of code actually work. This means covering all error scenarios in addition to testing with valid
requests
. For valid requests it may also be good to test that we get the data we expected, and likewise that our modifications actually take hold. With these things in mind, let's consider the first test: sensor collection get method test. We're also introducing the TestSensorCollection class.
class TestSensorCollection(object):

    RESOURCE_URL = "/api/sensors/"

    def test_get(self, client):
        resp = client.get(self.RESOURCE_URL)
        assert resp.status_code == 200
        body = json.loads(resp.data)
        assert len(body["items"]) == 3
        for item in body["items"]:
            assert "name" in item
            assert "model" in item
Because we created 3 sensors in the database population step, we're now ensuring that the API sends us all three, and that they have both of the attributes we expect them to have. This goes a bit beyond ensuring that the get method works. However, with this we can be sure that our API returns the data it is supposed to. For sensor collection's post method we have two options: we can wrap all the scenarios in one method, or we can put each
response
into its own. The examples below shows this as separate methods - the full example at the end of this material shows everything in one method. The first method tests with a valid request and also checks that we can find the resource we created using the response's location
header
.
    def test_post_valid_request(self, client):
        valid = _get_sensor_json()
        resp = client.post(self.RESOURCE_URL, json=valid)
        assert resp.status_code == 201
        assert resp.headers["Location"].endswith(self.RESOURCE_URL + valid["name"] + "/")
        resp = client.get(resp.headers["Location"])
        assert resp.status_code == 200
        body = json.loads(resp.data)
        assert body["name"] == "extra-sensor-1"
        assert body["model"] == "extrasensor"
The second method sends invalid
media type
. With Flask's test client this can be done by not using the json keyword argument, and instead dumping the dictionary as a string into the data argument.
    def test_post_wrong_mediatype(self, client):
        valid = _get_sensor_json()
        resp = client.post(self.RESOURCE_URL, data=json.dumps(valid))
        assert resp.status_code == 415
Another relatively simple test is sending a JSON document that doesn't pass through validation. In our case there is only one thing to test because our fields don't have value restriction: missing fields. For testing whether the method's validation handling works, one test case is sufficient.
    def test_post_missing_field(self, client):
        valid = _get_sensor_json()
        valid.pop("model")
        resp = client.post(self.RESOURCE_URL, json=valid)
        assert resp.status_code == 400
Finally we need to test for conflict. Sensor names are unique, so we should try sending a POST request with a name that's already taken, e.g. one of the test sensors we created in database population.
    def test_post_valid_request(self, client):
        valid = _get_sensor_json()
        valid["name"] = "test-sensor-1"
        resp = client.post(self.RESOURCE_URL, json=valid)
        assert resp.status_code == 409
On the item side, GET and PUT tests will look very similar and are thus not shown here - you can find them in the full example. That leaves DELETE test in which we should check that the deletion actually took by trying to send a GET request to the resource we just deleted.
class TestSensorItem(object):

    RESOURCE_URL = "/api/sensors/test-sensor-1/"
    INVALID_URL = "/api/sensors/non-sensor-x/"

    def test_delete_valid(self, client):
        resp = client.delete(self.RESOURCE_URL)
        assert resp.status_code == 204
        resp = client.get(self.RESOURCE_URL)
        assert resp.status_code == 404
And finally test that sending a DELETE request to a sensor that doesn't exist returns a 404 error:
    def test_delete_missing(self, client):
        resp = client.delete(self.INVALID_URL)
        assert resp.status_code == 404

Using Coverage

One nice tool to use with pytest is its coverage plugin. This plugin will track which lines of source code in the application being tested are executed during the tests. It's helpful in determining what kinds of tests are needed to ensure that every line in the program executes correctly. We already asked you to install the plugin along with pytest. We didn't use it for the database tests because database
models
didn't contain any callable code - class definitions are always executed as soon as the module imported, thus they will be always covered.
Now that we have some callable code in our
resource class
methods, we can also see the coverage plugin in action. Assuming a single file application, you can run pytest with the following command line arguments to get a coverage summary in the terminal:
pytest --cpv-report term-missing --cov=app
Where the --cov-report term-missing defines the reporting method to use and --cov=app defines for which module (or package) coverage should be tracked for. In our case we want to track our single file application, and we want a summary with line numbers printed for each line that is not covered. Using the test file at the end of this material, you should see something like this:
----------- coverage: platform linux, python 3.7.0-final-0 -----------
Name     Stmts   Miss  Cover   Missing
--------------------------------------
app.py     170      4    98%   289, 340, 346, 351
You can see all of the available reporting options in coverage plugin's documentation. The limitation of coverage is that it only shows you that lines have been executed, it doesn't say anything about whether they actually did what was expected. Even with a 100% coverage it is not safe to say that your program is fully working according to its specification - it is "merely" fully working (assuming all tests pass).

Hypermedia Tools

In API testing it is equally important that your API conforms to its documentation. Controls are one of the main selling points of
hypermedia
- in an ideal world, clients only need to concern themselves with controls that are available in
resource
representations. So in addition to testing that our API code works, we should also work towards ensuring that we send the correct controls along with resources reprenstations, and - going even one step further - ensure that those controls produce valid
requests
.
Since we want to only test that the control produces a valid request that results in a
response
of the 200 range, the tests for each
HTTP method
end up homogenic enough that we can make one helper function for each. For example, a function that tests a GET method control should take the
link relation
as a parameter, find the corresponding control object from the given document (or document part) and use the "href" attribute to send a request to the API server and assert that it got 200 as the response status code. Same in code:
def _check_control_get_method(ctrl, client, obj):

    href = obj["@controls"][ctrl]["href"]
    resp = client.get(href)
    assert resp.status_code == 200
A similar checking helper for DELETE controls is almost as simple. This time we just need to also check that the control actually defines the correct method to use in addition to the [term=URI!]URI[!term!].
def _check_control_delete_method(ctrl, client, obj):

    href = obj["@controls"][ctrl]["href"]
    method = obj["@controls"][ctrl]["method"].lower()
    assert method == "delete"
    resp = client.delete(href)
    assert resp.status_code == 204
POST and PUT methods require a bit more work, largely because we need to actually supply a valid object with the verification request. We're going to use another helper to generate one. We should also make sure there's a schema attached to the control. One way to check the schema is to use it as a basis for generating our request. This approach is used in this course's checkers a lot. However for this example we've taken a reverse approach and instead try to validate our (known to be valid) object against the schema found in the control. Here's the function for POST methods - PUT will look very similar.
def _get_sensor_json(number=1):
    return {"name": "extra-sensor-{}".format(number), "model": "extrasensor"}

def _check_control_post_method(ctrl, client, obj):
    ctrl_obj = obj["@controls"][ctrl]
    href = ctrl_obj["href"]
    method = ctrl_obj["method"].lower()
    encoding = ctrl_obj["encoding"].lower()
    schema = ctrl_obj["schema"]
    assert method == "post"
    assert encoding == "json"
    body = _get_sensor_json()
    validate(body, schema)
    resp = client.post(href, json=body)
    assert resp.status_code == 201
These helper functions should be put to use in GET method tests by calling the appropriate helper for each control the
resource
representation should have. Once again the API state diagram is worth its bytecount in gold here - every arrow that leaves a resource is a control that should be tested.

Full Example

You can download the full test suite that was described in this material from below. It contains tests for sensor collection and sensor items, and has 98% coverage. The four missing lines are related to unimplemented features Three of them are pass in a placeholder method, and one is only visited if a sensor has been assigned to a location - a feature that's not implemented yet.
resource_test.py
?
API Blueprint is a description language for REST APIs. Its primary categories are resources and their related actions (i.e. HTTP methods). It uses a relatively simple syntax. The advantage of using API Blueprint is the wide array of tools available. For example Apiary has a lot of features (interactive documentation, mockup server, test generation etc.) that can be utilized if the API is described in API Blueprint.
Another widely used alteranative for API Blueprint is OpenAPI.
Addressability is one of the key REST principles. It means that in an API everything should be presented as resources with URIs so that every possible action can be given an address. On the flipside this also means that every single address should always result in the same resource being accessed, with the same parameters. From the perspective of addressability, query parameters are part of the address.
Ajax is a common web technique. It used to be known as AJAX, an acronym for Asynchronous Javascript And XML but with JSON largely replacing XML, it become just Ajax. Ajax is used in web pages to make requests to the server without a page reload being triggered. These requests are asynchronous - the page script doesn't stop to wait for the response. Instead a callback is set to handle the response when it is received. Ajax can be used to make a request with any HTTP method.
  1. Kuvaus
  2. Examples
Anonymous functions are usually used as in-place functions to define a callback. They are named such because they are defined just like functions, but don't have a name. In JavaScript function definition returns the function as an object so that it can e.g. passed as an argument to another function. Generally they are used as one-off callbacks when it makes the code more readable to have the function defined where the callback is needed rather than somewhere else. A typical example is the forEach method of arrays. It takes a callback as its arguments and calls that function for each of its members. One downside of anonymous functions is that they function is defined anew every time, and this can cause significant overhead if performed constantly.
  1. Kuvaus
  2. Example
In Flask application context (app context for short) is an object that keeps tracks of application level data, e.g. configuration. You always need to have it when trying to manipulate the database etc. View functions will automatically have app context included, but if you want to manipulate the database or test functions from the interactive Python console, you need to obtain app context using a with statement.
Blueprint is a Flask feature, a way of grouping different parts of the web application in such a way that each part is registered as a blueprint with its own root URI. Typical example could be an admin blueprint for admin-related features, using the root URI /admin/. Inside a blueprint, are routes are defined relatively to this root, i.e. the route /users/ inside the admin blueprint would have the full route of /admin/users/.
Defines how data is processed in the application
Cross Origin Resource Sharing (CORS) is a relaxation mechanism for Same Origin Policy (SOP). Through CORS headers, servers can allow requests from external origins, what can be requested, and what headers can be included in those requests. If a server doesn't provide CORS headers, browsers will browsers will apply the SOP and refuse to make requests unless the origin is the same. Note that the primary purpose of CORS is to allow only certain trusted origins. Example scenario: a site with dubious script cannot just steal a user's API credentials from another site's cookies and make requests using them because the APIs CORS configuration doesn't allow requests from the site's origin. NOTE: this is not a mechanism to protect your API, it's to protect browser users from accessing your API unintentionally.
Callback is a function that is passed to another part of the program, usually as an argument, to be called when certain conditions are met. For instance in making Ajax requests, it's typical to register a callback for at least success and error situations. A typical feature of callbacks is that the function cannot decide its own parameters, and must instead make do with the arguments given by the part of the program that calls it. Callbacks are also called handlers. One-off callbacks are often defined as anonymous functions.
Piece of software that consumes or utilizes the functionality of a Web API. Some clients are controlled by humans, while others (e.g. crawlers, monitors, scripts, agents) have different degree of autonomy.
In databases, columns define the attributes of objects stored in a table. A column has a type, and can have additional properties such as being unique. If a row doesn't conform with the column types and other restrictions, it cannot be inserted into the table.
  1. Kuvaus
  2. Common keywords
In object relational mapping, column attributes are attributes in model classes that have been initialized as columns (e.g. in SQLAlchemy their initial value is obtained by initializing a Column). Each of these attributes corresponds to a column in the database table (that corresponds with the model class). A column attribute defines the column's type as well as additional properties (e.g. primary key).
Connectedness is a REST principle particularly related to hypermedia APIs. It states that there for each resource in the API, there must exist a path from every other resource to get there by following hypermedia links. Connectedness is easiest to analyze by creating an API state diagram.
Document Object Model (DOM) is an interface through which Javascript code can interact with the HTML document. It's a tree structure that follows the HTML's hierarchy, and each HTML tag has its own node. Through DOM manipulation, Javascript code can insert new HTML into anywhere, modify its contents or remove it. Any modifications to the DOM are updated into the web page in real time. Do note that since this is a rendering operation, it's very likely one of the most costly operations your code can do. Therefore changing the entire contents of an element at once is better than changing it e.g. one line at a time.
Database schema is the "blueprint" of the database. It defines what tables are contained in the database, and what columns are in each table, and what additional attributes they have. A database's schema can be dumped into an SQL file, and a database can also be created from a schema file. When using object relational mapping (ORM), the schema is constructed from model classes.
In HTML element refers to a single tag - most of the time including a closing tag and everything in between. The element's properties are defined by the tag, and any of the properties can be used to select that element from the document object model (DOM). Elements can contain other elements, which forms the HTML document's hierarchy.
In software testing, a fixture is a component that satisfies the preconditions required by tests. In web application testing the most common role for fixtures is to initialize the database into a state that makes testing possible. This generally involves creating a fresh database, and possibly populating it with some data. In this course fixtures are implemented using pytest's fixture architecture.
  1. Kuvaus
  2. Creating DB
  3. Starting the App
This term contains basic instructions about setting up and running Flask applications. See the term tabs "Creating DB" and "Starting the App". For all instructions to work you need to be in the folder that contains your app.
In database terminology, foreign key means a column that has its value range determined by the values of a column in another table. They are used to create relationships between tables. The foreign key column in the target table must be unique.
For most hypermedia types, there exists a generic client. This is a client program that constructs a navigatable user interface based on hypermedia controls in the API, and can usually also generate data input forms. The ability to use such clients for testing and prototyping is one of the big advantages of hypermedia.
HTTP method is the "type" of an HTTP request, indicating what kind of an action the sender is intending to do. In web applications by far the most common method is GET which is used for retrieving data (i.e. HTML pages) from the server. The other method used in web applications is POST, used in submitting forms. However, in REST API use cases, PUT and DELETE methods are also commonly used to modify and delete data.
HTTP request is the entirety of the requets made by a client to a server using the HTTP protocol. It includes the request URL, request method (GET, POST etc.), headers and request body. In Python web frameworks the HTTP request is typically turned into a request object.
Headers are additional information fields included in HTTP requests and responses. Typical examples of headers are content-type and content-length which inform the receiver how the content should be interpreted, and how long it should be. In Flask headers are contained in the request.headers attribute that works like a dictionary.
Host part is the part of URL that indicates the server's address. For example, lovelace.oulu.fi is the host part. This part determines where (i.e. which IP address) in the world wide web the request is sent.
In API terminology hypermedia means additional information that is added on top of raw data in resource representations. It's derived from hypertext - the stuff that makes the world wide web tick. The purpose of the added hypermedia is to inform the client about actions that are available in relation to the resource they requested. When this information is conveyed in the representations sent by the API, the client doesn't need to know how to perform these actions beforehand - it only needs to parse them from the response.
Instance folder is a Flask feature. It is intended for storing files that are needed when running the Flask application, but should not be in the project's code repository. Primary example of this is the prodcution configuration file which differs from installation to installation, and generally should remain unchanged when the application code is updated from the repository. The instance path can be found from the application context: app.instance_path. Flask has a reasonable default for it, but it can also be set manually when calling Flask constuctor by adding the instance_path keyword argument. The path should be written as absolute in this case.
  1. Kuvaus
  2. Serializing / Parsing
JavaScript Object Notation (JSON) is a popular document format in web development. It's a serialized representation of a data structure. Although the representation syntax originates from JavaScript, It's almost identical to Python dictionaries and lists in formatting and structure. A JSON document conists of key-value pairs (similar to Python dictionaries) and arrays (similar to Python lists). It's often used in APIs, and also in AJAX calls on web sites.
JSON schema is a JSON document that defines the validity criteria for JSON documents that fall under the schema. It defines the type of the root object, and types as well as additional constraints for attributes, and which attributes are required. JSON schemas serve two purposes in this course: clients can use them to generate requests to create/modify resources, and they can also be used on the API end to validate incoming requests.
  1. Kuvaus
  2. Common MIME types
MIME type is a standard used for indicating the type of a document.In web development context it is placed in the Content-Type header. Browsers and servers the MIME type to determine how to process the request/response content. On this course the MIME type is in most cases application/json.
Database migration is a process where an existing database is updated with a new database schema. This is done in a way that does not lose data. Some changes can be migrated automatically. These include creation of new tables, removal of columns and adding nullable columns. Other changes often require a migration script that does the change in multiple steps so that old data can be transformed to fit the new schema. E.g. adding a non-nullable column usually involves adding it first as nullable, then using a piece of code to determine values for each row, and finally setting the column to non-nullable.
  1. Kuvaus
  2. Example
In ORM terminology, a model class is a program level class that represents a database table. Instances of the class represent rows in the table. Creation and modification operations are performed using the class and instances. Model classes typically share a common parent (e.g. db.Model) and table columns are defined as class attributes with special constuctors (e.g. db.Column).
Object relational mapping is a way of abstracting database use. Database tables are mapped to programming language classes. These are usually called models. A model class declaration defines the table's structure. When rows from the database table are fetched, they are represented as instances of the model class with columns as attributes. Likewise new rows are created by making new instances of the model class and committing them to the database. This course uses SQLAlchemy's ORM engine.
In database terminology primary key refers to the column in a table that's intended to be the primary way of identifying rows. Each table must have exactly one, and it needs to be unique. This is usually some kind of a unique identifier associated with objects presented by the table, or if such an identifier doesn't exist simply a running ID number (which is incremented automatically).
Profile is metadata about a resource. It's a document intended for client developers. A profile gives meaning to each word used in the resource representation be it link relation or data attribute (also known as semantic descriptors). With the help of profiles, client developers can teach machine clients to understand resource representations sent by the API. Note that profiles are not part of the API and are usually served as static HTML documents. Resource representations should always contain a link to their profile.
In database terminology, query is a command sent to the database that can fetch or alter data in the database. Queries use written with a script-like language. Most common is the structured query language (SQL). In object relational mapping, queries are abstracted behind Python method calls.
  1. Kuvaus
  2. Example
Query parameters are additional parameters that are included in a URL. You can often see these in web searches. They are the primary mechanism of passing arbitrary parameters with an HTTP request. They are separated from the actual address by ?. Each parameter is written as a key=value pair, and they are separated from each other by &. In Flask applications they can be found from request.args which works like a dictionary.
  1. Kuvaus
  2. Examples
Regular expressions are used in computing to define matching patterns for strings. In this course they are primarily used in validation of route variables, and in JSON schemas. Typical features of regular expressions are that they look like a string of garbage letters and get easily out of hand if you need to match something complex. They are also widely used in Lovelace text field exercises to match correct (and incorrect) answers.
In this course request referes to HTTP request. It's a request sent by a client to an HTTP server. It consists of the requested URL which identifies the resource the client wants to access, a method describing what it wants to do with the resource. Requests also include headers which provide further context information, and possihby a request body that can contain e.g. a file to upload.
  1. Kuvaus
  2. Accessing
In an HTTP request, the request body is the actual content of the request. For example when uploading a file, the file's contents would be contained within the request body. When working with APIs, request body usually contains a JSON document. Request body is mostly used with POST, PUT and PATCH requests.
  1. Kuvaus
  2. Getting data
Request object is related to web development frameworks. It's a programming language object representation of the HTTP request made to the server. It has attributes that contain all the information contained within the request, e.g. method, url, headers, request body. In Flask the object can be imported from Flask to make it globally available.
in RESTful API terminology, a resource is anything that is interesting enough that a client might want to access it. A resource is a representation of data that is stored in the API. While they usually represent data from the database tables it is important to understand that they do not have a one-to-one mapping to database tables. A resource can combine data from multiple tables, and there can be multiple representations of a single table. Also things like searches are seen as resources (it does, after all, return a filtered representation of data).
Resource classes are introduced in Flask-RESTful for implementing resources. They are inherited from flask_restful.Resource. A resource class has a view-like method for each HTTP method supported by the resource (method names are written in lowercase). Resources are routed through api.add_resource which routes all of the methods to the same URI (in accordance to REST principles). As a consequence, all methods must also have the same parameters.
In this course response refers to HTTP response, the response given by an HTTP server when a request is made to it. Reponses are made of a status code, headers and (optionally) response body. Status code describes the result of the transaction (success, error, something else). Headers provide context information, and response body contains the document (e.g. HTML document) returned by the server.
Response body is the part of HTTP response that contains the actual data sent by the server. The body will be either text or binary, and this information with additional type instructions (e.g. JSON) are defined by the response's Content-type header. Only GET requests are expected to return a response body on a successful request.
Response object is the client side counterpart of request object. It is mainly used in testing: the Flask test client returns a response object when it makes a "request" to the server. The response object has various attributes that represent different parts of an actual HTTP response. Most important are usually status_code and data.
In database terminology, rollback is the cancellation of a database transaction by returning the database to a previous (stable) state. Rollbacks are generally needed if a transaction puts the database in an error state. On this course rollbacks are generally used in testing after deliberately causing errors.
  1. Kuvaus
  2. Routing in Flask
  3. Reverse routing
  4. Flask-RESTful routing
URL routing in web frameworks is the process in which the framework transforms the URL from an HTTP request into a Python function call. When routing, a URL is matched against a sequence of URL templates defined by the web application. The request is routed to the function registered for the first matching URL template. Any variables defined in the template are passed to the function as parameters.
In relational database terminology, row refers to a single member of table, i.e. one object with properties that are defined by the table's columns. Rows must be uniquely identifiable by at least one column (the table's primary key).
SQL (structured query language) is a family of languages that are used for interacting with databases. Queries typically involve selecting a range of data from one or more tables, and defining an operation to perform to it (such as retrieve the contents).
In web applications static content refers to content that is served from static files in the web server's hard drive (or in bigger installations from a separate media server). This includes images as well as javascript files. Also HTML files that are not generated from templates are static content.
In database terminology, a table is a collection of similar items. The attributes of those items are defined by the table's columns that are declared when the table is created. Each item in a table is contained in a row.
In software testing, test setup is a procedure that is undertaken before each test case. It prepares preconditions for the test. On this course this is done with pytest's fixtures.
In software testing, test teardown is a process that is undertaken after each test case. Generally this involves clearing up the database (e.g. dropping all tables) and closing file descriptors, socket connections etc. On this course pytest fixtures are used for this purpose.
Universal resource identifier (URI) is basically what the name says: it's a string that unambiguously identifies a resource, thereby making it addressable. In APIs everything that is interesting enough is given its own URI. URLs are URIs that specify the exact location where to find the resource which means including protocol (http) and server part (e.g. lovelace.oulu.fi) in addition to the part that identifies the resource within the server (e.g. /ohjelmoitava-web/programmable-web-project-spring-2019).
  1. Kuvaus
  2. Type converters
  3. Custom converters
URL template defines a range of possible URLs that all lead to the same view function by defining variables. While it's possible for these variables to take arbitrary values, they are more commonly used to select one object from a group of similar objects, i.e. one user's profile from all the user profiles in the web service (in Flask: /profile/<username>. If a matching object doesn't exist, the default response would be 404 Not Found. When using a web framework, variables in the URL template are usually passed to the corresponding view function as arguments.
In database terminology, unique constraint is a what ensures the uniqueness of each row in a table. Primary key automatically creates a unique constraint, as do unique columns. A unique constraint can also be a combination of columns so that each combination of values between these columns is unique. For example, page numbers by themselves are hardly unique as each book has a first page, but a combination of book and page number is unique - you can only have one first page in a book.
  1. Kuvaus
  2. Registering
View functions are Python functions (or methods) that are used for serving HTTP requests. In web applications that often means rendering a view (i.e. a web page). View functions are invoked from URLs by routing. A view function always has application context.
Interface, implemented using web technologies, that exposes a functionality in a remote machine (server). By extension Web API is the exposed functionality itself.