Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
# Lovdata

A PowerShell module for working with Norwegian legal data from [Lovdata](https://lovdata.no), the foundation that maintains the
authoritative, continuously updated body of Norwegian law. The module wraps the [Lovdata API](https://api.lovdata.no/swagger/index.html)
so laws (`lover`) and regulations (`forskrifter`) can be listed, inspected, and pulled into scripts as PowerShell objects instead of
scraped HTML.
authoritative, continuously updated body of Norwegian law.

**No account needed.** This release wraps the open, key-free part of the [Lovdata API](https://api.lovdata.no/swagger/index.html):
the current acts (`lover`) and central regulations (`forskrifter`) published as free open data under
[NLOD 2.0](https://data.norge.no/nlod/no/2.0), plus the service endpoints that report whether the API is up and which build is
deployed. Install the module and pull the full corpus of Norwegian acts in two commands, with nothing to configure and no
credential to obtain.

## Prerequisites

- PowerShell 7 or later on Windows, Linux, or macOS.
- An API key from Lovdata for the authenticated endpoints. Lovdata issues keys to users with the `api` role in their user base;
contact [api@lovdata.no](mailto:api@lovdata.no) to request one. The key is sent as the `X-API-Key` request header on every call.
- No key is needed for Lovdata's free public datasets, which are published under
[NLOD 2.0](https://data.norge.no/nlod/no/2.0). See [Lovdata's API information page](https://lovdata.no/info/api) for the background.
- No account, no API key, no configuration.

The API also rate limits each key. Responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers, and
the module surfaces the remaining budget on verbose output so long-running scripts can pace themselves.
The API rate limits every caller. Responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers,
and the module surfaces the remaining budget on verbose output so long-running scripts can pace themselves.

## Installation

Expand All @@ -27,42 +28,48 @@ Import-Module -Name Lovdata

## Capabilities

Store the API key once. It is encrypted at rest by the [Context](https://psmodule.io/Context/) module and reused by every
subsequent command, so scripts never carry the key themselves.
Check that the service is up and see which build is deployed:

```powershell
Connect-LovdataAccount -ApiKey (Read-Host -Prompt 'Lovdata API key' -AsSecureString)
Test-LovdataConnection
Get-LovdataApiVersion
```

List the legal sources the account can reach, then narrow to the ones of interest:
List the free open data packages Lovdata publishes, with the size and last-modified date of each:

```powershell
Get-LovdataLegalSource
Get-LovdataLegalSource -ID 'lov*'
Get-LovdataPublicDataset
Get-LovdataPublicDataset -FileName 'gjeldende-*'
```

Keep several keys side by side — one per environment or customer — and switch between them without reconnecting:
Download the current acts and central regulations to a folder, with progress and without silently overwriting existing files:

```powershell
Connect-LovdataAccount -ApiKey $productionKey -Context 'production'
Get-LovdataContext -ListAvailable
Switch-LovdataContext -Context 'production'
Get-LovdataPublicDataset -FileName 'gjeldende-*' | Save-LovdataPublicDataset -Path './lovdata'
```

Module-wide defaults, such as the API base URI, live in their own context and can be inspected or changed:
Point the module at a different API base URI for the session, for example a test deployment:

```powershell
Get-LovdataConfig
Set-LovdataConfig -Name ApiBaseUri -Value 'https://api.lovdata.no'
```

See the [examples](examples) folder for complete scripts, including downloading and unpacking the full corpus.

## Attribution

Lovdata publishes current laws and central regulations as open data under the
[Norwegian Licence for Open Government Data (NLOD) 2.0](https://data.norge.no/nlod/no/2.0). Content retrieved through this module
remains subject to Lovdata's terms; credit Lovdata as the source when redistributing it. This module is not affiliated with or
endorsed by Lovdata.

## The paid surface

Everything Lovdata offers behind an API key -- search, document retrieval, structured rules, vocabularies, reference resolution --
is not covered by this release. That authenticated surface, together with the credential store it needs, is tracked in
[PSModule/Lovdata#15](https://github.com/PSModule/Lovdata/issues/15).

## Documentation

Documentation is published at [psmodule.io/Lovdata](https://psmodule.io/Lovdata/).
Expand All @@ -71,5 +78,5 @@ Use PowerShell help and command discovery for module details:

```powershell
Get-Command -Module Lovdata
Get-Help -Name Get-LovdataLegalSource -Examples
Get-Help -Name Get-LovdataPublicDataset -Examples
```
8 changes: 5 additions & 3 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ triaged as quickly as possible.

## Credentials handled by this module

This module stores a Lovdata API key using the [`Context`](https://github.com/PSModule/Context) module, which encrypts secrets
at rest. Keys are never written to the repository, module source, or command output. If a key is exposed, revoke it with
Lovdata and remove the stored context with `Disconnect-LovdataAccount`.
This release handles no credentials. Everything it covers is Lovdata's open, key-free surface, so the module stores no API key
and no other secret, on disk or in memory. There is nothing for this module to leak.

The authenticated Lovdata surface, and the encrypted credential store it will need, are tracked separately in
[PSModule/Lovdata#15](https://github.com/PSModule/Lovdata/issues/15); this section will be revisited when that lands.

Problems with the Lovdata service itself, rather than with this module, belong with Lovdata's own tech support at
[api@lovdata.no](mailto:api@lovdata.no).
22 changes: 0 additions & 22 deletions examples/Get-LegalSources.ps1

This file was deleted.

30 changes: 30 additions & 0 deletions examples/Get-OpenDataPackages.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<#
.SYNOPSIS
Download the current Norwegian acts and regulations and unpack them locally.

.DESCRIPTION
Lists Lovdata's free open data packages, downloads the current acts and central regulations into a
local folder, and unpacks the .tar.bz2 archives with the tar tool that ships with PowerShell 7.
No account and no API key are needed. The unpacked content is published under NLOD 2.0; credit
Lovdata as the source when you redistribute it.
#>

Import-Module -Name Lovdata

$destination = Join-Path -Path (Get-Location) -ChildPath 'lovdata'
$null = New-Item -Path $destination -ItemType Directory -Force

# See what Lovdata publishes, with the size and last-modified date of each package.
Get-LovdataPublicDataset | Format-Table -Property FileName, SizeBytes, LastModified

# Download the current acts and central regulations, overwriting any earlier copies.
$packages = Get-LovdataPublicDataset -FileName 'gjeldende-*' |
Save-LovdataPublicDataset -Path $destination -Force

# Unpack each downloaded archive next to itself.
foreach ($package in $packages) {
$target = Join-Path -Path $destination -ChildPath $package.BaseName
$null = New-Item -Path $target -ItemType Directory -Force
tar -xjf $package.FullName -C $target
"Unpacked [$($package.Name)] into [$target]."
}
22 changes: 22 additions & 0 deletions examples/Test-ServiceAndListData.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<#
.SYNOPSIS
Check that the Lovdata API is reachable before running a data job.

.DESCRIPTION
Uses the open service endpoints to confirm the Lovdata API is up and to record which build is
deployed, then lists the available open data packages. All of this works with no account and no
API key, so it is a safe first step in an unattended script.
#>

Import-Module -Name Lovdata

if (-not (Test-LovdataConnection)) {
Write-Warning 'The Lovdata API is not reachable right now. Try again later.'
return
}

$version = Get-LovdataApiVersion
"Connected to Lovdata API [$($version.Name)] build [$($version.Timestamp)]."

# List the open data packages the service currently offers.
Get-LovdataPublicDataset | Format-Table -Property FileName, SizeBytes, LastModified
30 changes: 0 additions & 30 deletions examples/Use-MultipleContexts.ps1

This file was deleted.

32 changes: 32 additions & 0 deletions src/classes/public/LovdataApiVersion.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# The version of the deployed Lovdata API service, as reported by the '/version' endpoint.
class LovdataApiVersion {
# The name of the deployment, for example 'lovdata-api'.
[string] $Name

# The build timestamp of the deployment, for example '2026-07-31-1613'.
[string] $Timestamp

# The source revision the deployment was built from.
[string] $Revision

LovdataApiVersion() {}

LovdataApiVersion([hashtable] $Properties) {
foreach ($name in $Properties.Keys) {
$this.$name = $Properties[$name]
}
}

LovdataApiVersion([pscustomobject] $Object) {
$known = [LovdataApiVersion].GetProperties().Name
foreach ($property in $Object.PSObject.Properties) {
if ($known -contains $property.Name) {
$this.($property.Name) = $property.Value
}
}
}

[string] ToString() {
return '{0} {1}' -f $this.Name, $this.Timestamp
}
}
13 changes: 3 additions & 10 deletions src/classes/public/LovdataConfig.ps1
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
# Module-wide settings for the Lovdata module, stored in a module-scoped context so they are shared
# by every user context in the vault.
# Module-wide settings for the Lovdata module, kept in memory for the current session.
class LovdataConfig {
# The ID of the context that holds this configuration.
[string] $ID

# The base URI new contexts connect to, for example 'https://api.lovdata.no'.
# The base URI the module sends requests to, for example 'https://api.lovdata.no'.
[string] $ApiBaseUri

# The name of the context used by commands that are not given one explicitly.
[string] $DefaultContext

LovdataConfig() {}

LovdataConfig([hashtable] $Properties) {
Expand All @@ -28,6 +21,6 @@ class LovdataConfig {
}

[string] ToString() {
return $this.ID
return $this.ApiBaseUri
}
}
39 changes: 0 additions & 39 deletions src/classes/public/LovdataContext.ps1

This file was deleted.

29 changes: 0 additions & 29 deletions src/classes/public/LovdataLegalSource.ps1

This file was deleted.

35 changes: 35 additions & 0 deletions src/classes/public/LovdataPublicDataset.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# A public data package Lovdata publishes as free open data, such as the current acts or regulations.
class LovdataPublicDataset {
# The name of the package file, for example 'gjeldende-lover.tar.bz2'.
[string] $FileName

# The description Lovdata gives the package.
[string] $Description

# The size of the package in bytes.
[long] $SizeBytes

# When the package was last updated.
[datetime] $LastModified

LovdataPublicDataset() {}

LovdataPublicDataset([hashtable] $Properties) {
foreach ($name in $Properties.Keys) {
$this.$name = $Properties[$name]
}
}

LovdataPublicDataset([pscustomobject] $Object) {
$known = [LovdataPublicDataset].GetProperties().Name
foreach ($property in $Object.PSObject.Properties) {
if ($known -contains $property.Name) {
$this.($property.Name) = $property.Value
}
}
}

[string] ToString() {
return $this.FileName
}
}
Loading
Loading