The Federal Assembly - The Swiss Parliament
Welcome to the Swiss Parliament’s Open Data Webservice (OWS).
These guidelines should give advice about how to use RESTful APIs in general but also the OWS in particular. This interface sticks to generally established concepts for RESTful APIs as well as the Federal Administration API Guidelines of the Swiss Government.
RESTful APIs are designed to read, create, modify and delete data objects of certain types. Those types or entities are typically objects composed of one or more properties, which could for instance be primitive values, arrays or nested inner objects.
The data format used for RESTful APIs is not generally specified and can vary from JSON or XML to YAML. The Swiss Parliament API solely uses JSON for all server responses, though.
The different entities that are being served by a RESTful API are getting addresses by several HTTP URLs. All supported URLs of an API are called endpoints and are separated into two different kinds:
All endpoints typically follow a certain pattern. An entity gets a collection endpoint as well as a resource endpoint, which is the URL of the collection with an additional path parmeter for the ID. It can happen, that a single resource itself contains an individually maintainable collection of elements of a sub-entity. That results in another second-level collection and resource endpoints.
So a typical API structure looks like:
/library-api/v1/books
/library-api/v1/books/{bookID}
/library-api/v1/books/{bookID}/reservations
/library-api/v1/books/{bookID}/reservations/{reservationID}
To express the type of operation a client wants to perform, it calls the server on a certain HTTP URL using a particular HTTP method. Typical methods that are being used for RESTful APIs are:
| HTTP Method | Collection | Resource |
|---|---|---|
GET | Returns the full list available elements of the particular collection. Uses typically query parameters to allow filtering and/or sorting. | Returns the single element identified by the given ID. |
POST | Creates a new element, that is provided in the request body, in the particular collection. | < not supported > |
PUT | < not supported > | Modifies the selected element by replacing the entire content with the given data provided in the request body. |
PATCH | < not supported > | Modifies the selected element by replacing only single properties, that are provided in the request body. All properties that are not provided are left unchanged. |
DELETE | < not supported > | Deletes the single selected element. |
RESTful APIs use standard HTTP status codes to express the outcome of an operation. The status codes that are typically used with REST are:
| HTTP Status | Description |
|---|---|
| 200 | Successful operation. What ever has been requested was getting processed accordingly. |
| 201 | A POST operation was processed successfully and a new element has been created. |
| 204 | Successful operation with no response body. Similar to 200, only that no further data is returned. Typically used for delete operations. |
| 400 | Bad client request. Something was not correct, e.g. the data could not be parsed or it does not fulfill required constraints. |
| 401 | The client is unauthorized. This is typically the case when the client did not provide valid login credentials or API key. |
| 403 | The client is not allowed to perform the requested operation. This typically happens when an authorized client does not have enough permissions. |
| 404 | The resource could not be found. Either the URL is invalid or the addressed resource element does not exist. |
| 500 | Internal server error. Something server-side went wrong. |
The OWS provides public governmental information. This varies amongst others from data like councillors and parties over sessions and votes to processed businesses.
This data is provided via several endpoints of a RESTful API, that is fully specified using the OpenAPI specification in version 3.
Even though the service is publicly available, it requires an API key, that everyone can request by only using a valid email address. Once you have your API key available, it is used by sending it as part of each request in the HTTP header called X-API-KEY.
The API uses JSON for its representation, which by itself defines the datatypes:
The OWS supports a wider range of data types, though, which use one of the original JSON data types for their representation. The following tables outline all supported data types grouped by category and contain further details.
Scalar types are “basic” data types, that are not composed in any way and no collections of any kind. The following scalar types are supported on the API.
| Data Type | Data Subtypes | JSON Data Type | Description |
|---|---|---|---|
Boolean | Boolean, Scalar | Boolean | A simple boolean value, that can either be true or false. |
String | Text, Comparable, Scalar | String | Any sequence of characters, possibly with a length of zero, one or more. Strings can have an arbitrary length unless otherwise stated. |
Character | Text, Comparable, Scalar | String | Exactly one single character only. |
Integer | Number, Comparable, Scalar | Number | A number without decimal places, also known as a whole number, i.e. positive or negative. May contain a leading + or -, followed by one or more digits. Integers can have an arbitrary precision unless otherwise stated. |
Decimal | Number, Comparable, Scalar | Number | A positive or negative number with possibly decimal places. May contain a leading + or -, followed by one or more digits and an optional decimal part consisting of a . character as a separator and one or more digits. Decimal numbers can have an arbitrary precision unless otherwise stated. |
Instant | Temporal, Comparable, Scalar | Number | A point in time, represented by an integer number counting the seconds since epoch (January 1st, 1970 at 0:00) in UTC. |
LocalDate | Temporal, Comparable, Scalar | String | A date without any UTC offset or time zone information in ISO 8601 format: YYYY-MM-DD, example: 2024-05-19 |
LocalTime | Temporal, Comparable, Scalar | String | A time of a day without any UTC offset or time zone information in ISO 8601 format: hh:mm[:ss[.n{1-9}]], example: 16:42:03.332 |
LocalDateTime | Temporal, Comparable, Scalar | String | A date with a time of the day without any UTC offset or time zone information in ISO 8601 format: YYYY-MM-DDThh:mm[:ss[.{1-9}]], example: 1997-08-14T07:47 |
OffsetTime | Temporal, Comparable, Scalar | String | A time of a day including the offset to UTC in ISO 8601 format: hh:mm[:ss[.{1-9}]](+\|-)hh[:ss] or hh:mm[:ss[.{1-9}]]Z for Zulu (+00:00), example: 18:52+02:00 or 16:52Z |
OffsetDateTime | Temporal, Comparable, Scalar | String | A date with a time of the day including the offset to UTC in ISO 8601 format: YYYY-MM-DDThh:mm[:ss[.{1-9}]](+\|-)hh[:ss] or YYYY-MM-DDThh:mm[:ss[.{1-9}]]Z for Zulu (+00:00), example: 2021-11-14T19:12:53+01:00 or 2021-11-14T18:12:53Z |
ZonedDateTime | Temporal, Comparable, Scalar | String | A date with a time of the day including the offset to UTC and the timezone in ISO 8601 format: YYYY-MM-DDThh:mm[:ss[.{1-9}]](+\|-)hh[:ss][<TimeZone>], example: 2024-09-20T16:45:15.587+02:00[Europe/Berlin] |
Collections are data types, which are comprised of multiple elements of the same inner data type.
| Data Type | Data Subtypes | JSON Data Type | Description |
|---|---|---|---|
List | Collection | Array | An ordered collection of elements. |
Set | Collection | Array | An unordered collection of elements, that cannot contain any duplicate elements |
Objects are composed data types, that always consist of a property with a string name and its property value of any particular data type. Maps with a key of type String are a specialty, as they are treated as any regular object as well, where the key of any map entry corresponds to the property name and the entry’s value makes up the property value.
| Data Type | Data Subtypes | JSON Data Type | Description |
|---|---|---|---|
Map<String, T> | Object | Object | Object-like map. While filtering, allows the keys of the map to be used as “properties”, like on regular objects. |
| Any Arbitrary Object | Object | Object | Anything else, that is not one of the other data types. |
The null-value is not a data type per se, but can be used for any property of any type to express the absence of any actual value. This way, it is a clear difference if for instance a String is empty ("") or a List is empty ([]) or null.
Some properties are available as translated values. Whereas the API supports any number of languages, at the time of writing the following three languages are maintained in the underlying data set:
| Language | Code |
|---|---|
| German | de |
| French | fr |
| Italian | it |
The language can be selected by simply providing the appropriate language code to the query parameter lang as part of the request URL. If no language is selected, the default is German (de).
Example: /api/persons?lang=it
This lang parameter is available on every endpoint.
Any collection API-endpoint supports filtering the result set using a generic query expression. The filter query is passed in as a query parameter named q (for query) as part of the URL, for instance: /api/persons?q=...
It allows to select top-level elements that match the given expression. It is not possible to select only sub-elements or single properties of an element (also known as projections).
Every filter query expression is either a single match operation or a boolean expression.
Boolean expressions allow to negate or to join multiple sub-queries being either boolean and or boolean or combined. Match operations on the other hand allow to define a certain condition a property needs to comply to, to let the entire element appear in the query result.
Where boolean operators always take an entire “sub-query” (called condition), match operators work on properties that are compared to literal values. The only exception are collection-element match operators, that allow to apply conditions on elements of collections.
The full grammar looks as follows:
Query => Condition
Condition => BooleanOperator | MatchOperator
BooleanOperator => AndOperator | OrOperator | NotOperator
AndOperator => and(Condition [, Condition]*)
OrOperator => or(Condition [, Condition]*)
NotOperator => not(Condition)
MatchOperator => EqualsOperator | InOperator |
IsNullOperation | IsEmptyOperation | HasSizeOperation |
LowerThanOperation | LowerThanOrEqualOperation |
GreaterThanOperation | GreaterThanOrEqualOperation |
LikeOperation | RegexOperation | ContainsOperation |
AnyMatchOperation | AllMatchOperation | NoneMatchOperation
EqualsOperator => eq(PROPERTY_PATH, LITERAL)
InOperator => in(PROPERTY_PATH, LITERAL [,LITERAL]*)
IsNullOperation => isnull(PROPERTY_PATH)
IsEmptyOperation => isempty(PROPERTY_PATH)
HasSizeOperation => hassize(PROPERTY_PATH, LITERAL)
LowerThanOperation => lt(PROPERTY_PATH, LITERAL)
LowerThanOrEqualOperation => le(PROPERTY_PATH, LITERAL)
GreaterThanOperation => gt(PROPERTY_PATH, LITERAL)
GreaterThanOrEqualOperation => ge(PROPERTY_PATH, LITERAL)
LikeOperation => like(PROPERTY_PATH, LITERAL)
RegexOperation => regex(PROPERTY_PATH, LITERAL [,[i|m|x|s]+])
ContainsOperation => contains(PROPERTY_PATH, LITERAL [,LITERAL]*)
AnyMatchOperation => any(PROPERTY_PATH, Condition)
AllMatchOperation => all(PROPERTY_PATH, Condition)
NoneMatchOperation => none(PROPERTY_PATH, Condition)
To reference a property the API uses a dot-notation. The first property is always relative to the top-level object. If the top-level property is an object itself, you can reference a nested property by using a . (dot) and the name of the second-level property.
This can be extended for every further nesting level and has technically no limitations.
Example:
{
"firstName": "Daniel",
"lastName": "Stückrath",
"age": 53,
"contactInformation": {
"address": {
"street": "Bahnstrasse 17",
"zipCode": 3774,
"city": "Oberschwenden"
},
"telephoneNumbers": [
{
"type": "mobile",
"number": "0274 3827 4727"
},
{
"type": "private",
"number": "05774 3948 2838"
}
]
}
}
Valid Property Paths:
firstNamecontactInformationcontactInformation.address.zipCodecontactInformation.telephoneNumbersOnly when you use collection-element match operations, the property paths inside change to be relative to the referenced list element.
If you would like to query all persons, that have a mobile number available, you would use any(contactInformation.telephoneNumbers, eq(type, "mobile")). See how type inside the list element is used relative to the telephone number object.
Additionally, only inside the collection-element match operations you can use the this reference to address the entire collection element itself. This is required for example to apply a regex operation on elements of a collection of String values.
Example: any(activities, regex(this, "^Member of.*$"))
These Literals can be used as shorthands to replace commonly used values which are annoying to hard code.
| Literal | Allowed Property Types | Description |
|---|---|---|
now | LocalDate or LocalDateTime or LocalTime | Current date and/or time in server timezone. |
today | LocalDate | Current date in server timezone. |
As already outlined above, operators are used to express what condition needs to be fulfilled by a top-level element to be part of the query result list. We differentiate between three categories of operators.
| Operator | Long Name | Parameters | Description |
|---|---|---|---|
and | boolean and | Condition+ | Joins all provided conditions to a boolean and combination. |
or | boolean or | Condition+ | Joins all provided conditions to a boolean or combination. |
not | negation | Condition | Negates the provided condition. |
| Operator | Long Name | Parameters | Allowed Property Types | Description |
|---|---|---|---|---|
eq | equals | Property, Literal | All Scalar types | Matches if the property’s value equals the expected value. |
in | is in / is one of | Property, Literal+ | All Scalar types | Matches if the property’s value equals any of the given expected values. |
isnull | is null | Property | All types | Matches if the property’s value is null. |
isempty | is empty | Property | String and Collections | Matches if the String or Collection property is empty (size of zero). |
hassize | has size of | Property, Literal | String and Collections | Matches if the String or Collection property has the expected length/size |
lt | lower than | Property, Literal | All Comparable types | Matches if the Comparable property is lower than the provided value. |
le | lte | lower than or equals | Property, Literal | All Comparable types | Matches if the Comparable property is lower than or equal to the provided value. |
gt | greater than | Property, Literal | All Comparable types | Matches if the Comparable property is greater than the provided value. |
ge | gte | greater than or equals | Property, Literal | All Comparable types | Matches if the Comparable property is greater than or equal to the provided value. |
like | is like | Property, Literal | String | Matches if the String property matches the given Glob-Pattern. The pattern matches exactly as given, except that a ? wildcard-character matches any single character and the * wildcard-character matches any arbitrary number of characters. |
regex | matches regex | Property, Literal, (optional) RegexFlags | String | Matches if the String property matches the given regular expression. The following RegEx options are supported: i (case-insensitive), m (multiline = ^ and $ match at the very beginning/end instead of each line’s beginning/end), x (extended = ignore whitespace unless escaped or in character-class) and s (dot-all = . dot character also matches newline characters). |
contains | contains | Property, Literal+ | Collections containing Scalar-type elements | Matches if the Collection property contains all given elements (compared by performing an eq operation). |
| Operator | Long Name | Parameters | Allowed Property Types | Description |
|---|---|---|---|---|
any | any element matches | Property, Condition | Collections | Matches if at least one element in the collection complies to the given condition. |
all | all elements match | Property, Condition | Collections | Matches if all elements in the collection comply to the given condition. Beware that empty collections always match, because “all available elements” meet the condition. To exclude empty collections, use and(not(isempty(collection)), all(collection, <your condition>) |
none | no element matches | Property, Condition | Collections | Matches if no element in the collection complies to the given condition. Beware that empty collections always match, because “no element” meets the condition. To exclude empty collections, use and(not(isempty(collection)), none(collection, <your condition>) |
If you filter on String properties which have translations available, the filtering is applied to the value of the (effectively) selected language. This way it is recommended to explicitly select the language as part of the URL if you want to filter on translated String values, and not to rely on the default language code instead.
Any collection API-endpoint supports sorting by defining the sort order in a query parameter called sort. Sorting is applied only to the top-level elements, though. Nested inner collections can not be re-ordered and the effective ordering is undefined and no assumptions should be made about it.
Sorting is defined by one or more properties with a sort order (ascending or descending). Any property, where the sort order is omitted, is sorted in ascending order. The sequence of properties in the sort expression matters. Sorting is applied first by ordering the top-level elements by the values of the first property. Only for all elements, where the value of the first property is the same, those elements are sorted by the second specified property and so on.
Referencing a property uses the dot-notation and follows the same rules as used for filtering. See here for further details. Just be aware, that for sorting you cannot use collections anywhere on the path, because the result would be undefined. Nested properties are supported as long as the final target property is always a scalar-type property. See chapter Scalar Types for details on those data types.
The full grammar looks as follows:
SortExpression => PropertyOrder [, PropertyOrder]*
PropertyOrder => PROPERTY_PATH[:(asc|desc)]
Using the example of a person’s JSON representation in chapter Property Paths, the following sort expressions are examples of how to use sorting:
sort=firstName or sort=firstName:ascsort=lastName,firstNamesort=contactInformation.address.zipCode:descsort=age:desc,telephoneNumbers.numbertelephoneNumbers is a collection, which cannot be used for sortingsort=contactInformation.addressaddress is correctly nested, but is of data type Object, which cannot be used for sorting. Use any inner property instead, e.g. city or zipCodeThe OWS provides the ability to include or exclude specific attributes from the response using the include and exclude query parameters. This allows clients to optimize payload size and retrieve only the necessary fields.
include:exclude:contactInformation.telephoneNumbers).include is set, the exclude parameter is ignored.Given the following full response from the API:
{
"firstName": "Daniel",
"lastName": "Stückrath",
"age": 53,
"contactInformation": {
"address": {
"street": "Bahnstrasse 17",
"zipCode": 3774,
"city": "Oberschwenden"
},
"telephoneNumbers": [
{
"type": "mobile",
"number": "0274 3827 4727"
},
{
"type": "private",
"number": "05774 3948 2838"
}
]
}
}
If the request specifies the following include parameter:
?include=firstName,lastName,contactInformation.telephoneNumbers
The response will contain only the specified attributes:
{
"firstName": "Daniel",
"lastName": "Stückrath",
"contactInformation": {
"telephoneNumbers": [
{
"type": "mobile",
"number": "0274 3827 4727"
},
{
"type": "private",
"number": "05774 3948 2838"
}
]
}
}
If the request specifies the following exclude parameter:
?exclude=contactInformation,age
The response will include all attributes except the specified ones:
{
"firstName": "Daniel",
"lastName": "Stückrath"
}
The OWS supports and enforces the usage of pagination. Any collection endpoint returns its resulting elements in a page of a particular size. Depending on the total number of available elements there can be one or more pages available you have to “scroll” through to read the full response.
As part of any collection response, the API informs about the current page’s size and index as well as the number of total elements and total pages available. The page size can be chosen up until a maximum of 1000 elements. Changing the page size between queries to a sequence of pages is not recommended, as it would lead to either missing or duplicate elements.
All collection endpoints support the following two query parameters to use pagination:
page:0 (first page) if omitted.size:50 if omitted and is limited to 1000.withCounts:withCounts=true, the response includes additional pagination metadata, namely the total number of elements (totalElements) and the total number of pages (totalPages). This allows for precise navigation and estimation of remaining pages.withCounts is not set or set to false, the response does not include totalElements and totalPages, and clients should rely on the hasNext field to determine if there are more pages available. Omitting withCounts results in a faster response since fewer calculations are required.When withCounts=true, the pagination object looks like this:
{
"content": [
...
],
"page": {
"hasNext": true,
"number": 0,
"size": 50,
"totalElements": 520,
"totalPages": 13
}
}
When withCounts is not set or explicitly set to false, the pagination object is returned without totalElements and totalPages:
{
"content": [
...
],
"page": {
"hasNext": true,
"number": 0,
"size": 50,
"totalElements": null,
"totalPages": null
}
}
Clients relying on pagination should consider whether they need full count information or if they prefer the faster response provided when withCounts is omitted.
The API uses explicit as well as a default versioning.
Every endpoint exists with an explicit versioning as part of the URL. Example:
/api/v1/persons
Every version stays stable and compatible regarding the following scenarios:
On the other hand, the following changes must be accepted by the client and are not considered as a breach of compatibility:
All endpoints of the latest API version additionally exist without a version number in the URL. This results in using endpoints without an explicit version to default to the newest available one. Example:
/api/persons
As a consequence, if your application relies on a stable interface, please use all endpoints with an explicit version number in the URL. Otherwise, any version upgrade might result in errors on your client applications.
The filter query language is defined by a formal ANTLR 4 grammar. The grammar file is published alongside this documentation and can be downloaded directly:
ANTLR 4 can generate a parser in many target languages (Java, Python, JavaScript/TypeScript, Go, C#, C++, Swift, and more). To generate a parser for your language:
antlr4 -Dlanguage=<Target> APIFilterQueryV1.g4APIFilterQueryV1Lexer and APIFilterQueryV1Parser classesNote: antlr4 requires the ANTLR 4 tool JAR on your classpath or the antlr4 alias configured (see the download page). For targets other than Java, add the corresponding ANTLR 4 runtime as a dependency in your project.
The grammar defines three entry points:
query — filter expression (used with the q parameter)sorting — sort expression (used with the sort parameter)fields — field inclusion/exclusion (used with include / exclude parameters)For full ANTLR 4 documentation and target language runtimes, see antlr.org.