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
    7. Control
  4. D
    1. DOM
    2. Database Schema
  5. E
    1. Element
    2. Entry Point
  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. Idempotent
    2. 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. N
    1. Namespace
  14. O
    1. ORM
  15. P
    1. Primary Key
    2. Profile
  16. Q
    1. Query
    2. Query Parameter
  17. R
    1. Regular Expression
    2. Request
    3. Request Body
    4. Request Object
    5. Resource
    6. Resource Class
    7. Resource Representation
    8. Response
    9. Response Body
    10. Response Object
    11. Rollback
    12. Routing
    13. Route
      Routing
    14. Row
  18. S
    1. SQL
    2. Serialization
    3. Static Content
  19. T
    1. Table
    2. Test Setup
    3. Test Teardown
  20. U
    1. URI
    2. URL Template
    3. Uniform Interface
    4. Unique Constraint
  21. V
    1. View Function
    2. Virtualenv
  22. W
    1. Web API
Ratkaistu: / tehtävää

Learning Outcomes and Material

During this exercise students will learn how to design a
Hypermedia
API. Students will learn also how to document their API using Apiary, a professional documentation framework. We expect that you follow the same process as the one described in this exercise in order to complete the Deliverable 3.
The slides presenting the content of the lecture can be downloaded from the following link:
Exercise 2 slides.pdf
In addition, we included an additional set of slides containing main hypermedia formats that you can use in your project work. We recommend you to choose either Collection+JSON or Mason.
Hypermedia appendix.pdf
More on hypermedia formats can be found from the course material. We recommend:

Hypermedia API Design and Documentation

This exercise material is a more hands-on tutorial to design considerations regarding (hypermedia) APIs. It also introduces one particular tool for documenting APIs. The material tells you - through examples - what is required from your API documentation for deadline 3 of the project work. While it may sound a bit backward that we're asking you to document your API before implementing it, there's a couple of reasons. First of all, we want you to really focus on the interface when designing your API. You should think about the best ways for the clients to access your API. If you implement before documeting, your API will instead be based on your implementation and its limitations. Second, this way you will receive feedback about your API before implementing it. It's much easier to make corrections on the design and documentation than on an implemented API.
This material mostly follows the requirements in your project report. We will outline the API concept and then move on to making a fully documented REST API that uses
hypermedia
for
resource
representations. We'll explain the design decisions as we go, which will hopefully help you understand REST concepts and the use of hypermedia.
Please note that this material has been written with the expectation that the reader is familiar with RESTful API concepts from the lecture materials or relevant course book chapters.

API Concept

The API concept in this material is a service that stores metadata about music. The metadata is split into three levels: artist, album and track. The API can be used to enrich music-related data from other sources, and can also be used to fill in partial metadata of a poorly managed music collection. This example is interesting because the problem domain has some peculiar characteristics that require additional design considerations. It's also a good API example because its primary clients are machines.
The data schema is not particularly large: artists are authors of albums which contain tracks. So we have a clear hierarchy that is easy enough to represent in a database.

Challenges

The first challenge related to the problem domain is that names of artists, albums or tracks are not generally not trademarkable. In other words they are not unique. You can find multiple artists - sometimes even from the same country - with the exact same name. The same goes for album names. On the other hand, artists typically don't have multple albums with the same name. Usually albums don't have multiple tracks with the same name either but there's an exception: there can be multiple untitled tracks on an album. One way or another our API needs to navigate this non-uniqueness mess.
The second challenge is the existence of "various artists" releases (VA for short), i.e. collaborative works. These are albums that have multiple artists, with one or more tracks from each. With these releases each track has to have its artist defined separately unlike normal releases where all tracks on an album are by the same artist. So although these two types of releases are very similar, they are not identical and will require some degree of differing treatment.

Related Services

This example API provides similar data as two free services for music metadata: Musicbrainz and FreeDB. These services are often used when ripping audio files from CDs because they have a CD checksum lookup for metadata. Of course our example is more limited but it is a RESTful API unlike these two. There's also Rate Your Music which offers meta information for human users.
An example of a data source that can be used with this API is last.fm which is a tracking site for your personal music listening. It has a lot of metadata of its own but one tragic failing: it is unable to track listening time accurately as the primary statistcs are listening counts per track. This means that the statistics are biased towards artists that have shorter average track length. Not to worry, last.fm has its own API. It would be possible to pull data from there and combine with the length metadata from our proposed API!

Database Design

From our concept we can easily come up with a database that has three
models
: album, artist and track. However we also need to consider the VA exception when designing these models, so we actually have two additional item types to represent: VA album and VA track. We also need to figure out
unique constraints
for each model. Although everything in the database has a unique primary key, you should never use raw database IDs to address resources in an API. First of all they don't mean anything. Second, it introduces vulnerabilities for APIs that don't want unauthorized clients to infer details about the content.
Unique constraint allows us to define more complex definitions of uniqueness than just defining individual columns as unique. A combination of multiple columns can be made into a unique constraint so that a certain combination of values in these columns can only appear once. For example, we can probably assume that the same artist is not going to have multiple albums with the same name (we're not counting separate editions). So while album title by itself cannot be unique, album title combined with the artist ID foreign key can.
def Album(db.Model):
    __table_args__ = (db.UniqueConstraint("title", "artist_id", name="_artist_title_uc"), )
Please note the comma at the end: this tells Python that this is a 1 item tuple, not a single value in regular parenthesis. You can list as many as column names for the unique constraint as you want. The name at the end doesn't matter, but has to exist, so better make it descriptive. For individual tracks we have an even better unique constraint: each album can only have one track at each disc index (per disc). So the unique constraint for tracks is a combinaton of album ID, track number and disc number.
def Track(db.Model):
    __table_args__ = (db.UniqueConstraint("disc_number", "track_number", "album_id", name="_track_index_uc"), )
We're going to solve the VA problem by allowing an album's artist foreign key to be null, and by adding an optional va_artist field to tracks. We'll make this mandatory for VA tracks on the application logic side later. Overall our database code ends up looking like this:
models.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.engine import Engine
from sqlalchemy import event
from sqlalchemy.exc import IntegrityError, OperationalError

app = Flask(__name__, static_folder="static")
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///development.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)

@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
    cursor = dbapi_connection.cursor()
    cursor.execute("PRAGMA foreign_keys=ON")
    cursor.close()

va_artist_table = db.Table("va_artists", 
    db.Column("album_id", db.Integer, db.ForeignKey("album.id"), primary_key=True),
    db.Column("artist_id", db.Integer, db.ForeignKey("artist.id"), primary_key=True)
)


class Track(db.Model):
    
    __table_args__ = (db.UniqueConstraint("disc_number", "track_number", "album_id", name="_track_index_uc"), )
    
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String, nullable=False)
    disc_number = db.Column(db.Integer, default=1)
    track_number = db.Column(db.Integer, nullable=False)
    length = db.Column(db.Time, nullable=False)
    album_id = db.Column(db.ForeignKey("album.id", ondelete="CASCADE"), nullable=False)
    va_artist_id = db.Column(db.ForeignKey("artist.id", ondelete="SET NULL"), nullable=True)
    
    album = db.relationship("Album", back_populates="tracks")
    va_artist = db.relationship("Artist")

    def __repr__(self):
        return "{} <{}> on {}".format(self.title, self.id, self.album.title)
    
    
class Album(db.Model):
    
    __table_args__ = (db.UniqueConstraint("title", "artist_id", name="_artist_title_uc"), )
    
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String, nullable=False)
    release = db.Column(db.Date, nullable=False)
    artist_id = db.Column(db.ForeignKey("artist.id", ondelete="CASCADE"), nullable=True)
    genre = db.Column(db.String, nullable=True)
    discs = db.Column(db.Integer, default=1)
    
    artist = db.relationship("Artist", back_populates="albums")
    va_artists = db.relationship("Artist", secondary=va_artist_table)
    tracks = db.relationship("Track",
        cascade="all,delete",
        back_populates="album",
        order_by=(Track.disc_number, Track.track_number)
    )
    
    sortfields = ["artist", "release", "title"]
    
    def __repr__(self):
        return "{} <{}>".format(self.title, self.id)


class Artist(db.Model):
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    unique_name = db.Column(db.String, nullable=False, unique=True)
    formed = db.Column(db.Date, nullable=True)
    disbanded = db.Column(db.Date, nullable=True)
    location = db.Column(db.String, nullable=False)
    
    albums = db.relationship("Album", cascade="all,delete", back_populates="artist")
    va_albums = db.relationship("Album",
        secondary=va_artist_table,
        back_populates="va_artists",
        order_by=Album.release
    )

    def __repr__(self):
        return "{} <{}>".format(self.name, self.id)

From it you can also see how to set default ordering for relationships and a couple of other things that weren't covered in the previous exercise.

Resource Design

We're now ready to design the
resources
provided by our API. An important takeaway from this section is how we turn three database
models
into (way) more than three resources. We will also explain how
HTTP methods
are used in this API by following REST principles.

Resources from Models

A resource should be something that is interesting enough to be given its own
URI
in our service. Likewise each resource must be uniquely identifiable by its URI. It's quite common for an API to have at least twice as many resources as it has database
tables
. This follows from a simple reasoning: for each table, a client might be interested in the table as a collection, or just in an individual
row
in the table. Even if the collection
representation
has all the stored data about each of its items, the item representation must also exist if we want to enable clients to manipulate them.
If we were to follow this very simple reasoning, we'd have 6 resources:
  1. artist collection
  2. artist item
  3. album collection
  4. album item
  5. track collection
  6. track item
It is worth noting that a collection type resource doesn't necessarily have to contain the entire contents of the associated table. For instance contextless track collection makes very little sense; a collection of tracks by album makes more sense. In fact an album is a collection of tracks, so having a separate track collection resource might not even make sense. Artist collection is simple enough because artist is on top of the hierarchy, so it makes sense for the collection to have all artists. What about albums though? Like tracks, it does make sense to have "albums by an artist" as a collection resource. But we also have VA albums to worry about. We can make two collection resources: one for an artist's albums and another for VA albums. We end up with:
  1. artist collection
  2. artist item
  3. albums by artist collection
  4. VA albums collection
  5. album item (incorporates track collection)
  6. track item
However, we have slightly different representation for VA albums compared to normal albums, and same goes for tracks. Even though we chose the same
model
to represent both, they do have ever so slightly different requirements to be valid: for normal albums, we must know the artist; for VA album tracks we must know the track artist. So it would be fair to say that these are in fact separate
representations
that should be added as resources. Finally let's add a collection of all albums so that clients can see what albums our API has data for.
  1. artist collection
  2. artist item
  3. all albums collection
  4. albums by artist collection
  5. VA albums collection
  6. album item (incorporates track collection)
  7. VA album item (incorpotes VA track collection)
  8. track item
  9. VA track item
Bonus consideration: Why are we incorporating track collection into album, but not incorporating album colletion into artist? Mostly because artist as a concept is more than a collection of albums. For example artist could also be a collection of people (band members). The API should state what it means explicitly, and therefore it is better to separate "artist" from "albums by artist".

Routing Resources

After identifying what's considered important enough (and different enough) to be regarded as its own
resource
, we now have to come up with
URIs
so that each can be uniquely identified (
addressability principle
). This also defines our URI hierarchy. We want the URIs to convey the relationships between our resources. For normal albums the hierarchy goes like this:
artist collection
└── artist
    └── album collection
        └── album
            └── track
We decided that album title paired with artist ID is sufficient for
uniqueness
. We also decided that the best way to uniquely identify a track is to use its position an the album as an index consisting of disc and track numbers. Taking all this into account, we end up with a route that looks like this:
/api/artists/{artist_unique_name}/albums/{album_title}/{disc}/{track}/
This uniquely identifies each track, and also clearly shows the hierarchy. All the intermediate resources (both collections and items) can be found by dropping off parts from the end. We will separate VA albums from the rest by using VA to replace {artist}, ending up with this route to identify each VA track:
/api/artists/VA/albums/{album_title}/{disc}/{track}/
Then we need to add one more separate branch to the URI tree for the collection that shows all albums:
/api/albums/
The entire URI tree becomes:
api
├── artists
│   ├── {artist}
│   │   └── albums
│   │       └── {album}
│   │           └── {disc}
│   │               └── {track}
│   └── VA
│       └── albums
│           └── {album}
│               └── {disc}
│                   └── {track}
└── albums

Resource Actions

Following REST principles our API should offer actions as
HTTP methods
targeted at resources. To reiterate, each HTTP method should be used as follows:
Most resources should therefore implement GET. Collection types usually implement POST whereas PUT and DELETE are typically attached to individual items. In our case we make two exceptions: first, as album serves as both an item and as a collection, it actually implements all four; second, the albums resource at the bottom of the URI tree above should not provide POST because there is no way of knowing from the URI which artist is the author. The parent of a new item should always be found from the URI - not in the
request body
. We're not using PATCH in this example.
Gathering everything into a table:
Resource URI GET POST PUT DELETE
artist collection /api/artists/ X X - -
artist item /api/artists/{artist}/ X - X X
albums by artist /api/artists/{artist}/albums/ X X - -
albums by VA /api/artists/VA/albums/ X X - -
all albums /api/albums/ X - - -
album /api/artists/{artist}/albums/{album}/ X X X X
VA album /api/artists/VA/albums/{album}/ X X X X
track /api/artists/{artist}/albums/{album}/{disc}/{track}/ X - X X
VA track /api/artists/VA/albums/{album}/{disc}/{track}/ X - X X
Since we are following the
uniform interface
REST principle and each HTTP method does what it's expected to, this table actually tells a lot about our API: it shows every possible
HTTP
request that can be made and even hints at their meaning: if you send a PUT request to a track resource, it will modify the track's data (even more specifically it will replace all data with what's in the request body). It just doesn't do a very good job of explaining what requests and responses should look like.

Just Add Happiness

Using everything we've told you about the API so far, what URI do you need to use if you want to add the track "Happiness" (third track on Kallocain, album by Paatos). For this task, the artist's unique name is simply the artist's name in lowercase.
Type the URI (no server part) below
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Enter Hypermedia

In order for client developers to know what to actually send - and what to expect in return - APIs need to be documented. On this course we are using
hypermedia
in responses given by the API. This solves part of the documentation issue because the API itself describes possible actions that can be taken to the client. For this example we have chosen Mason as our hypermedia format because it has a very clear syntax for defining hypermedia elements and connecting them to data.

Data Representation

Our API communicates in
JSON
. There isn't a whole lot to data representation really, it's a rather straightforward
serialization
process from
model
instance attributes to JSON attributes. If the client sends a GET request to, say, /api/artists/scandal/ the data that is returned would be serialized into this:
{
    "name": "Scandal",
    "unique_name": "scandal",
    "location": "Osaka, JP",
    "formed": "2006-08-21",
    "disbanded": null
}
Likewise if the client wants to add a new artist, they'd send almost an identical JSON document, sans unique_name because it is generated by the API server. A similar serialization process can be applied for all models. Collection type resources will have "items" attribute which is an array containing objects that are part of the collection. Most notably albums have both root level data about the album itself, and an array of tracks. It's also worth noting that collection types don't necessarily have to include all the data about their members. For example in album collections we have deemed it sufficient to show album title and artist name:
{
    "items": [
        {
            "artist": "Scandal",
            "title": "Hello World"
        },
    ]
}
If the client wants more information about the album, it can always send a GET to the album resource itself. But how does it know how to do that?

Hypermedia Controls and You

You can consider the API as a map and each
resource
as a node. The resource that you most recently sent a GET request to is basically the node that says "you are here".
Hypermedia
controls
describe the logical next actions: where to go next, or actions that can be performed with the particular node you're in. Together with the resources they actually form a client-side state diagram of how to navigate the API. Hypermedia controls are extra attributes attached to the data
representation
we just saw.
A hypermedia control is a combination of at least two things:
link relation
("rel") and target
URI
("href"). These answer two questions: what does this control do, and where to go to activate it. Note that link relation is a machine-readable keyword, not a description for humans. Many generally used relations are being standardized (full list) but APIs can define their own when needed as well - as long as each relation always means the same thing. When a client wants to do something, it uses the available link relations to discover what URI the next request should go to. This means that clients using our API should never need to have hardcoded URIs - they will find the URI by searching for the correct relation instead.
Mason also defines some additional attributes for hypermedia controls. Of these "method" is one that we will be using frequently, because it tells which
HTTP method
should be used to make the request (usually omitted for GET as it is assumed to be the default). There's also "title" which can be used in
generic clients
(or other generated clients) to help the client's human user figure out what the control does. Even beyond that we can also include JSON schema representation that defines how to send data to the API.
In Mason hypermedia controls can be attached to any object by adding the "@controls" attribute. This in itself is an object where link relations are attribute names whose values are also objects that have at least one attribute: href. For example, here is a track item with controls to get back to the album it is on ("up") and to edit its information ("edit"):
{
    "title": "Wings of Lead Over Dormant Seas",
    "disc_number": 2,
    "track_number": 1,
    "length": "01:00:00",
    "@controls": {
        "up": {
            "href": "/api/artists/dirge/albums/Wings of Lead Over Dormant Seas/"
        },
        "edit": {
            "href": "/api/artists/dirge/albums/Wings of Lead Over Dormant Seas/2/1/",
            "method": "PUT"
        }
    }
}
Or if we want each item in a collection to actually have its own URI available to clients:
{
    "items": [
        {
            "artist": "Scandal",
            "title": "Hello World",
            "@controls": {
                "self": {
                    "href": "/api/artists/scandal/albums/Hello World/"
                }
            }
        },
        {
            "artist": "Scandal",
            "title": "Yellow",
            "@controls": {
                "self": {
                    "href": "/api/artists/scandal/albums/Yellow/"
                }
            }
        }
    ]
}

Custom Link Relations

While it's good to use standards as much as possible, realistically each API will have a number of
controls
whose meaning cannot be explicitly conveyed with any of the standardized
relations
. For this reason Mason documents can use link relation
namespaces
to extend available link relations. A Mason namespace defines a prefix and its associated namespace (similar to XML namespace, see CURIEs). The prefix will be added to link relations that are not defined in the IANA list.
When a relation is prefixed with a namespace prefix, it is meant to be interpreted as attaching the relation at the end of the namespace and makes the relation unique - even if another API defined a relation with the same name, it would have a different namespace in front. For example if want to have a relation called "albums-va" to indicate a control that leads to a collection of all VA albums, its full identifier could be http://wherever.this.server.is/musicmeta/link-relations/#albums-by. To make this look less wieldy we can define a namespace prefix called "mumeta", and then include this control like so:
{
    "@namespaces": {
        "mumeta": {
            "name": "http://wherever.this.server.is/musicmeta/link-relations/#"
        }
    },
    "@controls": {
        "mumeta:albums-va": {
            "href": "/api/artists/VA/albums"
        }
    }
}
Also if a client developer visits the full URL, they should find a description about the link relation. Note also that this is normally expected to be a full URL because the server part is what guarantees uniqueness. In later examples you will see we're using a relative
URI
- this way the link to the relation description itself works even if the server is running in a different address (i.e. most likely localhost:someport).
Information about the link relations must be stored somewhere. Note that this is intended for client developers i.e. humans. In our case a simple HTML document with anchors for each relation should be sufficient. This is why our namespace name ends with #. It makes it convenient to find each relation's description. Before moving on, here's the full list of custom link relations our API uses: add-album, add-artist, add-track, albums-all, albums-by, albums-va, artists-all, delete.

API Map

The last order of business in designing our API is to create a full map with all the
resources
and
hypermedia
controls
visible. This a kind of a state diagram where resources are states and controls are transitions. Generally speaking only GET methods are used to moving from one state to another because other methods don't return a
resource representation
. We have presented other methods as arrows that circle back to the same state. Here's the full map in all its glory.
MusicMeta API state diagram
NOTE: The box color codes are only included for educational purposes to show you how data from the database is connected to resources - you don't need to share implementation details like this in real life, or your course project for that matter.
NOTE 2: the
link relation
"item" does not exist, this is actually "self". In this diagram "item" is used to indicate that this is a transition to an item from a collection through the item's "self" link.
A map like this is useful when designing the API and should be done before designing individual representations returned by the API. As all actions are visible in a single diagram, it's easier to see if something is missing. When making the diagram keep in mind that there must be a path from every state to every other state (
connectedness
principle). In our case we have three separate branches in the
URI
tree and therefore we have to make sure to include transitions between brances (e.g. AlbumCollection
resource
has "artists-all" and "albums-va").

The Road to Transcendence

Consider the above state diagram. Let's assume you're a machine client. You are currently standing in the ArtistCollection node. The goal is to find and modify data about a various artists album titled "Transcendental" (collaboration of Mono and The Ocean). Which links have to be followed in order to do that? Does that path make sense to you?
For your answer, type the shortest list of link relations (use same names as in the diagram) that lead you from ArtistCollection to modifying the VA album's data.
Write the relations on a single line, separated with commas.
Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Entry Point

A final note about mapping API is the
entry point
concept. This should be at the root of the API (in our case: /api/. It's kind of like the API's index page. It's not a
resource
, and isn't generally returned to (which is why it isn't in the diagram). It just shows the reasonable starting options a client has when "entering" the API. In our case it should have
controls
to GET either the artists collection or the albums collection (potentially also the VA album collection).

Enter the Maze

Create a JSON document of the MusicMeta APIs entry point. It should contain two hypermedia controls: link to the artist collection, and link to the albums collection. You should be able to figure out the link relations of these controls from the state diagram. Don't forget to use the mumeta namespace!
UPDATE: the checker has been changed from a static examiner to a system that generates requests using your JSON document and sends them to the reference server
Return your JSON file here.

Sallitut tiedostojen nimet

Varoitus: Et ole kirjautunut sisään. Et voi vastata.

Advanced Controls with Schema

Up to now we have defined possible actions by using
hypermedia
. Each action comes with a
link relation
that has an explicit meaning, address for the associated resource, and the
HTTP method
to use. This information is sufficient for GET and DELETE requests, but not quite there for POST and PUT - we still don't know what to put in the
request body
. Mason supports adding
JSON Schema
to hypermedia controls. The schema defines what kind of
JSON
document will be considered valid by the API. As an example, here's the complete schema for albums:
{
    "type": "object",
    "properties": {
        "title": {
            "description": "Album title",
            "type": "string"
        },
        "release": {
            "description": "Release date",
            "type": "string",
            "pattern": "^[0-9]{4}-[01][0-9]-[0-3][0-9]$"
        },
        "genre": {
            "description": "Album's genre(s)",
            "type": "string"
        },
        "discs": {
            "description": "Number of discs",
            "type": "integer",
            "default": 1
        }
    },
    "required": ["title", "release"]
}
For objects, the schema itself is made of three attributes:
Properties generally have "description" (for human readers) and "type". They can also have some other attributes as seen in the example: pattern - a
regular expression
that defines what kinds of values are valid for this attribute (compatible with strings only); default which is the value taken by this attribute in case it is omitted. These are just some basic things JSON schema can do. You can read more from its specification.
A schema object like this one can be attached to a Mason hypermedia
control
by assigning it to the "schema" attribute. If the schema is particularly large or you have another reason to not include it in the response body, you can alternatively provide the schema from a URL on your API server (e.g. /schema/album/) and assign the URL to the "schemaUrl" attribute so that clients can retrieve it. The client can then use the schema to form a proper request when sending data to your API. Whether a machine client can figure out what to put into each attribute is a different story. One option is to use names that conform to a standard e.g. we could use the same attribute names as IDv2 tags in MP3 files.
Schemas are particularly useful for (partially) generated clients that have human users. It's quite straightforward to write a piece of code that generates a form from a schema so that the human user can fill it. We'll show this in the last exercise of the course. On the API side schemas actually pull a double duty - they can be used to validate the client's requests too (e.g. with this). It's probably worth noting that the date pattern in our example is not foolproof (it'd accept something like 2000-19-39) which must be taken into account in the implementation. A completely foolproof regex would be quite a bit longer - feel free to see if you can come up with one.
Schemas can also be used for resources that use
query parameters
. In this case they will described the available parameters and values that are accepted. As an example we can add a query parameters that affects how the all albums collection is sorted. Here's the "mumeta:albums-all" control with the schema added. Note also the addition of "isHrefTemplate", and that "type": "object" is omitted from the schema.
{
    "@controls": {
        "mumeta:albums-all": {
            "href": "/api/albums/?{sortby}",
            "title": "All albums",
            "isHrefTemplate": true,
            "schema": {
                "properties": {
                    "sortby": {
                        "description": "Field to use for sorting",
                        "type": "string",
                        "default": "title",
                        "enum": ["artist", "title", "genre", "release"]
                    }
                },
                "required": []
            }
        }
    }
}

Client Example

In order to give you some idea about why we're going through all this trouble and adding a bunch of bytes to our payloads, let's consider a small example from the client's perspective. Our client is a submission bot that browses its local music collection and sends metadata to the API for artists/albums that do not exist there yet. Let's say its local collection is grouped by artists, then albums. Let's say it's currently examining an artist folder ("Miaou") that contains one album folder ("All Around Us"). The goal is to see if this artist is in the collection, and whether it has this album.
  1. bot enters the api and finds the artist collection by looking for a
    hypermedia
    control
    named "mumeta:artists-all"
  2. bot sends a GET to the artist collection using the hypermedia control's href attribute
  3. bot looks for an artist named "Miaou" but doesn't find it
  4. bot looks for "mumeta:add-artist" hypermedia control
  5. bot compiles a POST request using the control's href attribute and the associated
    JSON schema
  6. after sending the POST request, the bot discovers the artist's address from the response's location
    header
  7. bot sends a GET to the address it received
  8. from the artist representation the bot looks for the "mumeta:albums-by" hypermedia control
  9. bot send a GET to the control's href attribute, receiving an empty album collection
  10. since the album is not there, bot looks for "mumeta:add-album" control
  11. bot compiles a POST request using the control's href attribute and the associated JSON schema
The important takeaway from this example is that the bot doesn't need to now any
URIs
besides /api/. For everything else it has been programmed to look for
link relations
. All the addresses it visits are parsed from the responses it gets. They could be completely arbitrary and the bot would still work. Depending on the bot's AI it can survive quite drastical API changes (for example when it GETs the artist representation and finds a bunch of controls, how exactly has it been programmed to follow "mumeta:albums-by"?)
One really cool thing about hypermedia APIs is that they usually have a generic client to browse any API if it's valid. The client will generate a human-usable web site by using hypermedia controls to provide links from one view to another, and schemas to generate forms.

Hypermedia Profiles

By adding
hypermedia
we have managed to create APIs that machine clients can navigate once they have been taught the meaning of each
link relation
, and the meaning of each attribute in
resource representations
. But how exactly does the machine learn these things? This is a ongoing challenge for API development - for now one way is to educate the human developers by using resource
profiles
. Profiles describe the semantics of resources in human-readable format. This way human developers can transfer this knowledge to their client, or a human user of a client can use this knowledge when navigating the API.

What's in a Profile?

There's no universal consensus about what exactly should be in a profile, or how to write one. Regardless of how it's written, the profile should have semantic descriptors for attributes (of the resource representation) and protocol semantics for actions that can be taken (or a list of link relations associated with the resource). Collections don't necessarily have their own profiles, like in our example they don't. Except for album since it is both an item and a collection.
If your resource represents something that is relatively common, using attributes defined in a standard (or standard proposal) is recommended. If your entire resource representation can conform to a standard, all the better. You can look for standards in https://schema.org/. One important future step for our example API would be to use attributes from this schema for albums and tracks.

Distributing Profiles

Like
link relations
, information about your
profiles
should be accessible from somewhere. In our example we have chosen to distribute them as HTML pages from the server using
routing
/profiles/{profile_name/. Links to profiles can be inserted as
hypermedia
controls
using the "profile" link relation. For example, to link the track profile from a track
representation
:
{
    "@controls": {
        "profile": {
            "href": "/profiles/track/"
        }
    }
}
Another possibility is to use HTTP Link
header
in responses.
Link: <http://where.ever.the.server.is/profiles/track/>; rel="profile"
However this is somewhat more ambiguous. Our album
resource
is an example that actually should link to two profiles - album and track. For this reason we have included profiles as hypermedia controls, and for collection types we have included one with every item.

API Documentation

Ultimately your API is only as good as its documentation. APIs should be documented using one of the prevalent standards, i.e. API Blueprint or OpenAPI. Both standards come with a nice set of related tools: from documentation browsing to automated test generation (see API Blueprint tools section for way more examples). For this exercise we have chosen to use API Blueprint, and the Apiary editor for creating interactive documentation.
The syntax of API Blueprint is relatively simple. You can start by going through the official tutorial. You can learn the rest from our example. You should also create an Apiary account and use the editor there for going through the remaining examples and tasks.

Describing a Resource

This is a very brief guide about how each
resource
should be represented in your documentation. Resource description starts with its name, followed by its
URI
in square braces, e.g. Underneath you can write a human-readable description.
## Album Collection [/api/albums/]
If the resource URI contains variables, these should be described as parameters, like this:
## Albums by Artist [/api/albums/{artist}/]

+ Parameters

    + artist (string) - artist's unique name (unique_name)
After this, each action should be described using a descriptive title and
HTTP method
. This can be followed by a human-readable description.
### List all albums [GET]
For each action, you should include its
link relation
. You also need to include a request section, and response sections for each possible status code. All of these sections should also contain examples of valid requests, and of API responses. For example, documentation for Albums by Artist's GET method (message bodies omitted for brevity, see the full example later).
### List albums by artist [GET]

+ Relation: albums-by
+ Request

    + Headers
    
            Accept: application/vnd.mason+json
    
+ Response 200 (application/vnd.mason+json)

    + Body
            ...

+ Response 404 (application/vnd.mason+json)

    + Body
            ...

Hypermedia Issue

Warning: intentional tool abuse ahead. We have one inconvenience when using these otherwise very nice standards: they don't support
hypermedia
. That is to say, the syntax doesn't have any way for including
link relations
or
resource
profiles
into the same document. This is why we are actually just serving the from the server as HTML files. However for our API Blueprint examples, and also for the final task, we're actually just going to do a little bit of abuse. More specifically, we are going to include two groups: link relations and profiles, and inside those groups each link relation and profile will be added using the syntax for resources.
Doing this creates documentation that is nicer to browse for humans as everything will appear neatly in the index, and we can put anchor links inside the documentation for quick access to different sections. However, this intentional abuse does not play nicely with automated tools because they try to treat everything as resources. There are existing proposals to include hypermedia properly into the syntax, but for now we have only these two options: either we don't include link relation and profile information in the Apiary documentation, or we put them in as "resources".

API Blueprint Example

Below is an example that documents the album-related resources of our API. The text file itself is rather long; if you want to get a better browsing experience, we'd recommend that you copypaste the contents into a new Apiary project.
musicmeta.md
Apiary editor view after pasting
Important caution: the editor doesn't seem to autosave. Be sure to mash the Save button religiously after changes - just make sure your document is valid first (and yes, do fix warnings). Everything should be indented with 1 tab or 4 spaces, except body elements - those should be indented twice in relation to the + Body section header.
You can also go to the Documentation tab to browse the API documentation using the whole screen width. Click on the various requests in the document to open details about that request (and possible responses) to the right side of the documentation browser.

API Blueprint Artist

We're totally not done with lame pun titles. To wrap up this exercise and learn a bit of API Blueprint, we want you to fulfill part of the Music Meta API documentation. The example we provided contains the album resource group. Your job is to add the resource group for artists.
Learning goals: Learn how to write valid API Blueprint syntax. Learn how to properly document a resource.
Before you begin:
You should make your additions to the example. If you haven't downloaded it yet and put it into Apiary, do so now. Add the resource group for artists, and start working on two new resource descriptions. You should also keep the state diagram from earlier at hand, as well as the database models we showed in the beginning. As a general tip: follow the examples. Your resource descriptions must contain all the same information. You can come up with your own artist examples for the data.
Artist Collection resource
The artist collection includes all artists. For each artist, all column values except ID are shown in their collection entries, using the same names as the database columns. The resource supports two methods: GET to retrieve the description, and POST to create a new artist.
For GET you must include an example response body which includes all the controls leading away from the ArtistCollection resource in the state diagram. Note that some of the controls are located artist entries, not in the root level, and don't forget to use namespaces. Also note that add-artist needs to include a JSON schema. The response body should also include at least one artist's data. The artist entries should be an array in the "items" attribute, and the first artist must be one that you know to exist (i.e. one from the other examples, or the one in your POST example request).
For POST you must include a valid example request body that has values for all fields. You must also include responses for the following error codes: 400 and 415. You don't need to include response bodies.
Artist resource
The artist resource includes the same information as the collection for one artist. The resource supports three methods: GET, PUT and DELETE. The resource should describe an artist that you know to exist.
For GET you must include an example response body which includes all the controls leading away from the Artist resource in the state diagram. The edit link must also include a JSON schema. In addition to the 200 reponse, also add 404 (no response body needed).
For PUT you must include a valid example request body that has values for all fields. You must also include responses for the following error codes: 400, 404, 415.
For DELETE you just need to have responses with the correct status codes. The only error is 404.
UPDATE: The checker is now live. It performs tests by generating requests using information from your API blueprint and its JSON example requests/responses. This is once again very experimental technology, let us know if there are any problems.
Upload your API Blueprint file here.

Sallitut tiedostojen nimet

Varoitus: Et ole kirjautunut sisään. Et voi vastata.
?
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.
  1. Kuvaus
  2. Example
A hypermedia control is an attribute in a resource representation that describes a possible action to the client. It can be a link to follow, or an action that manipulates the resource in some way. Regardless of the used hypermedia format, controls include at least the URI to use when performing the action. In Mason controls also include the HTTP method to use (if it's not GET), and can also include a schema that describes what's considered valid for the request body.
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.
For APIs entry point is the "landing page" of the API. It's typically in the API root of the URL hierarchy and contains logical first steps for a client to take when interacting with the API. This means it typically has one or more hypermedia controls which usually point to relevant collections in the API or search functions.
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.
An idempotent operation is an operation that, if applied multiple times with the same parameters, always has the same result regardless of how many times it's applied. If used properly, PUT is an idempotent operation: no matter how many times you replace the contents of a resource it will have the same contents as it would have if only one request had been made. On the other hand POST is usually not idempotent because it attempts to create a new resource with every request.
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).
  1. Kuvaus
  2. Example
In API terminology, namespace is a prefix for names used by the API that makes them unique. The namespace should be a URI, but it doesn't have to be a real address. However, usually it is convenient to place a document that described the names within the namespace into the namespace URI. For our purposes, namespace contains the custom link relations used by the API.
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 we use the term representation to emphasize that a resource is, in fact, a representation of something stored in the API server. In particular you can consider representation to mean the response sent by the API when it receives a GET request. This representation contains not only data but also hypermedia controls which describe the actions available to the client.
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).
Serialization is a common term in computer science. It's a process through which data structures from a program are turned into a format that can be saved on the hard drive or sent over the network. Serialization is a reversible process - it should be possible to restore the data structure from the representation. A very common serialization method in web development is JSON.
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.
Uniform interface is a REST principle which states that all HTTP methods, which are the verbs of the API, should always behave in the same standardized way. In summary:
  • GET - should return a representation of the resource; does not modify anything
  • POST - should create a new instance that belongs to the target collection
  • PUT - should replace the target resource with a new representation (usually only if it exists)
  • DELETE - should delete the target resource
  • PATCH - should describe a change to the resource
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.
  1. Kuvaus
  2. Creation
  3. Activation
A Python virtual environment (virtualenv, venv) is a system for managing packages separately from the operating system's main Python installation. They help project dependency management in multiple ways. First of all, you can install specific versions of packages per project. Second, you can easily get a list of requirements for your project without any extra packages. Third, they can placed in directories owned by non-admin users so that those users can install the packages they need without admin privileges. The venv module which is in charge of creating virtual environments comes with newer versions of Python.
Interface, implemented using web technologies, that exposes a functionality in a remote machine (server). By extension Web API is the exposed functionality itself.