Skip to content
Nick Steinwachs edited this page Sep 19, 2025 · 9 revisions

Welcome to the willow_sword wiki!

Welcome to the Notch8 willow_sword fork wiki! For the full legacy documentation, please see CottageLabs/willow_sword/wiki. This fork provides SWORD V2 support for Valkyrized Hyrax implementations.

NOTE: This fork only supports Valkyrized Hyrax implementations.

Hyku's SWORD V2 API Documentation

Overview

Hyku 6 comes with WillowSword pre-installed and ready to use. All tenants can utilize WillowSword's SWORD V2 implementation for depositing and managing content, provided they have a valid API key. This document describes the SWORD V2 endpoints serviced by the willow_sword engine.

Installation

Add this line to your application's Gemfile:

gem 'willow_sword', git: 'https://github.com/notch8/willow_sword.git'

And then execute:

$ bundle
$ bundle exec rails generate willow_sword:install

Mount the engine in config/routes.rb:

mount WillowSword::Engine => '/sword'

Configuration

Configure in config/initializers/willow_sword.rb:

WillowSword.setup do |config|
  # The title used by the sword server, in the service document
  config.title = 'Hyrax Sword V2 server'
  # Default collection if not using collections in Sword
  config.default_collection = {id: 'default', title: ['Default collection']}
  # Model names for retrieving collections (based on Hyrax integration)
  config.collection_models = ['Collection']
  # Work models supported by Sword
  config.work_models = ['Work']
  # FileSet model supported by Sword
  config.file_set_models = ['FileSet']
  # Remove parameters not in model's permitted attributes
  config.allow_only_permitted_attributes = true
  # XML mappings
  config.xml_mapping_create = 'DC'
  config.xml_mapping_read = 'DC'
  # Authorize Sword requests using Api-key header
  config.authorize_request = true
  # Default work model when none provided
  config.default_work_model = 'GenericWork'
end

Authentication

All requests require an API key to be included in the headers:

Api-key: example-key-12345

Failure to provide a valid API key will result in a 403 Forbidden response.

API Key Generation

Currently, API keys can only be generated by developers with access to the Rails console:

require 'securerandom'
u = User.find_by_email('hyku_user@instance.test')
u.api_key = SecureRandom.uuid
u.save!

Metadata Namespaces

The following metadata namespaces are used in SWORD responses:

Prefix Namespace URI Description
dc http://purl.org/dc/elements/1.1/ Dublin Core (DC) elements for broad compatibility
dcterms http://purl.org/dc/terms/ Dublin Core Terms (DC Terms), an extended set of metadata elements
h4cmeta https://hykucommons.org/schema/metadata Hyku Commons-specific metadata for descriptive elements
h4csys https://hykucommons.org/schema/system Hyku Commons-specific system metadata (e.g., internal identifiers)

Example error response:

<?xml version="1.0"?>
<error xmlns="http://purl.org/net/sword/error/">
  <title>Bad Request</title>
  <summary>Title is required</summary>
  <sword:treatment>processing failed</sword:treatment>
  <generator uri="https://demo.hykucommons.org/" version="2.0"/>
</error>

Acknowledgments

This implementation is based on the original WillowSword gem created by Cottage Labs CottageLabs/willow_sword. The fork was necessary to modernize the gem for compatibility with Hyrax's Valkyrie resources, moving away from the previous ActiveFedora implementation.

# Welcome to the willow_sword wiki!

Welcome to the Notch8 willow_sword fork wiki! For the full legacy documentation, please see [CottageLabs/willow_sword/wiki](https://github.com/CottageLabs/willow_sword/wiki). This fork provides SWORD V2 support for Valkyrized Hyrax implementations.

NOTE: This fork only supports Valkyrized Hyrax implementations.

Hyku's SWORD V2 API Documentation

Overview

Hyku 6 comes with WillowSword pre-installed and ready to use. All tenants can utilize WillowSword's SWORD V2 implementation for depositing and managing content, provided they have a valid API key. This document describes the SWORD V2 endpoints serviced by the willow_sword engine.

Installation

Add this line to your application's Gemfile:

gem 'willow_sword', git: 'https://github.com/notch8/willow_sword.git'

And then execute:

$ bundle
$ bundle exec rails generate willow_sword:install

Mount the engine in config/routes.rb:

mount WillowSword::Engine => '/sword'

Configuration

Configure in config/initializers/willow_sword.rb:

WillowSword.setup do |config|
  # The title used by the sword server, in the service document
  config.title = 'Hyrax Sword V2 server'
  # Default collection if not using collections in Sword
  config.default_collection = {id: 'default', title: ['Default collection']}
  # Model names for retrieving collections (based on Hyrax integration)
  config.collection_models = ['Collection']
  # Work models supported by Sword
  config.work_models = ['Work']
  # FileSet model supported by Sword
  config.file_set_models = ['FileSet']
  # Remove parameters not in model's permitted attributes
  config.allow_only_permitted_attributes = true
  # XML mappings
  config.xml_mapping_create = 'DC'
  config.xml_mapping_read = 'DC'
  # Authorize Sword requests using Api-key header
  config.authorize_request = true
  # Default work model when none provided
  config.default_work_model = 'GenericWork'
end

Authentication

All requests require an API key to be included in the headers:

Api-key: example-key-12345

Failure to provide a valid API key will result in a 403 Forbidden response.

API Key Generation

Currently, API keys can only be generated by developers with access to the Rails console:

require 'securerandom'
u = User.find_by_email('hyku_user@instance.test')
u.api_key = SecureRandom.uuid
u.save!

Metadata Namespaces

The following metadata namespaces are used in SWORD responses:

Prefix Namespace URI Description
dc http://purl.org/dc/elements/1.1/ Dublin Core (DC) elements for broad compatibility
dcterms http://purl.org/dc/terms/ Dublin Core Terms (DC Terms), an extended set of metadata elements
h4cmeta https://hykucommons.org/schema/metadata Hyku Commons-specific metadata for descriptive elements
h4csys https://hykucommons.org/schema/system Hyku Commons-specific system metadata (e.g., internal identifiers)

Dublin Core vs. Dublin Core Terms

Dublin Core Terms (dcterms) is a superset of the original Dublin Core (dc) metadata standard. While Hyrax/Hyku primarily uses DC Terms, the SWORD response also includes DC elements to support legacy clients that may only recognize the dc namespace whenever possible.

Example feed:

<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      xmlns:dcterms="http://purl.org/dc/terms/" 
      xmlns:h4cmeta="https://hykucommons.org/schema/metadata" 
      xmlns:h4csys="https://hykucommons.org/schema/system">
  <title>A Test, For Documentation</title>
  <content rel="src" href="https://demo.hykucommons.org/sword/collections/default/works/some-work-id"/>
  <link rel="edit" href="https://demo.hykucommons.org/sword/collections/default/works/some-work-id/file_sets"/>
  <entry>
    <content rel="src" href=".../file_sets/some-file-set-id"/>
    <link rel="edit" href=".../file_sets/some-file-set-id"/>
  </entry>
  <h4csys:id>some-work-id-1234</h4csys:id>
  <h4csys:internal_resource>Image</h4csys:internal_resource>
  <h4csys:created_at>2024-07-10 23:04:45 UTC</h4csys:created_at>
  <h4csys:updated_at>2025-02-05 22:19:27 UTC</h4csys:updated_at>
  <h4cmeta:title>A Test</h4cmeta:title>
  <h4cmeta:title>For Documentation</h4cmeta:title>
  <dc:title>A Test</dc:title>
  <dcterms:abstract>This is the abstract, it's so short!</dcterms:abstract>
  <!-- ... additional metadata fields ... -->
</feed>

Admin Sets & Collections

The service document will deliver collection elements representing both Admin Sets and Collections. The type child element will describe this with values of "AdminSet" and "Collection".

Type Description
AdminSet Represents an Admin Set in Hyrax, used for policy and workflow control
Collection Represents a Collection, created by end users to organize works

Example feed

<feed xmlns="http://www.w3.org/2005/Atom">
  <title>A Collection</title>
  <type>Collection</type>
  <link rel="edit" href="https://demo.hykucommons.org/sword/collections/some-collection-id/works"/>
  <entry>
    <content rel="src" href=".../works/some-work-id"/>
    <link rel="edit" href=".../works/some-work-id/file_sets"/>
  </entry>
</feed>

Base URL

Replace https://demo.hykucommons.org with your instance's base URL in all examples.

Work Type & Admin Set Configuration

Setting the Work Type

To specify a work type when creating a new work, add the Hyrax-Work-Model header to your request:

Hyrax-Work-Model: Etd

You can pass either the standard name (e.g., Etd) or the resource name (e.g., EtdResource). The system will prioritize creating the Valkyrie version (EtdResource) when available.

If this header is not included, the system will default to GenericWorkResource.

Setting the Admin Set

There are two ways to specify the Admin Set for a new work:

  1. Via URL (Recommended): Include the Admin Set ID in the URL path:

    https://demo.hykucommons.org/sword/collections/{admin_set_id}/works/
    

    Example:

    curl --request POST \
      --url https://demo.hykucommons.org/sword/collections/e01455cb-9877-4c28/works/ \
      --header 'Hyrax-Work-Model: Etd' \
      --header 'Api-key: example-key-12345' \
      --data-binary @metadata.xml
  2. Via Metadata XML (not in spec with SWORD): Include the Admin Set ID in the metadata XML:

    <admin_set_id>e01455cb-9877-4c28-aa1c-012caa000642</admin_set_id>

If the Admin Set ID is not provided through either method, or if an invalid ID is used, the system will default to the Default Admin Set.

To deposit into the default admin set, use the string default:

--url https://demo.hykucommons.org/sword/collections/default/works/

Note: When depositing to a Collection (not an Admin Set), you should continue to use the collection ID in the metadata XML.

Response Format

When creating a work, the response includes the work ID and file set IDs:

<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Molecular Mechanisms Controlling Immunity</title>
  <content rel="src" href=".../works/ddb7aef4-ef23-4cdb-a777-78d3f35126d9"/>
  <link rel="edit" href=".../works/ddb7aef4-ef23-4cdb-a777-78d3f35126d9/file_sets"/>
  <entry>
    <content rel="src" href=".../file_sets/c7426a7f-def1-481d-abf3-dcd54b5c9ef2"/>
    <link rel="edit" href=".../file_sets/c7426a7f-def1-481d-abf3-dcd54b5c9ef2"/>
  </entry>
  <!-- Additional file entries may be listed here -->
</feed>

Endpoints

1. Get Service Document

Retrieves the SWORD service document describing available collections and accepted package formats.

Request:

curl --request GET \
  --url https://demo.hykucommons.org/sword/service_document \
  --header 'Content-Type: application/xml' \
  --header 'Api-key: example-key-12345'

2. Get Collection

Returns a list of works in the specified collection.

Request:

curl --request GET \
  --url https://demo.hykucommons.org/sword/collections/example-collection-id-12345 \
  --header 'Content-Type: application/xml' \
  --header 'Api-key: example-key-12345'

3. Add New Work (Metadata Only)

There are two methods to create a new work with metadata only:

a. Binary Data Method

Request:

curl --request POST \
  --url https://demo.hykucommons.org/sword/collections/example-admin-set-id-12345/works \
  --header 'Content-Disposition: attachment; filename=metadata.xml' \
  --header 'Content-Type: application/xml' \
  --header 'In-Progress: false' \
  --header 'On-Behalf-Of: admin@example.com' \
  --header 'Packaging: application/atom+xml;type=entry' \
  --header 'Hyrax-Work-Model: Etd' \
  --header 'Api-key: example-key-12345' \
  --data-binary @dc.xml

b. Form Data Method

Request:

curl --request POST \
  --url https://demo.hykucommons.org/sword/collections/example-admin-set-id-12345/works \
  --header 'In-Progress: false' \
  --header 'On-Behalf-Of: admin@example.com' \
  --header 'Hyrax-Work-Model: Etd' \
  --header 'Api-key: example-key-12345' \
  -F metadata=@dc.xml

4. Add New Work with Files

Several methods are available for adding works with associated files:

a. Zip File Method (Binary)

Request:

curl --request POST \
  --url https://demo.hykucommons.org/sword/collections/example-admin-set-id-12345/works/ \
  --header 'Content-Disposition: attachment; filename=testPackage.zip' \
  --header 'Content-Type: application/zip' \
  --header 'In-Progress: false' \
  --header 'On-Behalf-Of: admin@example.com' \
  --header 'Packaging: http://purl.org/net/sword/package/SimpleZip' \
  --header 'Hyrax-Work-Model: Etd' \
  --header 'Api-key: example-key-12345' \
  --data-binary @testPackage.zip

b. Form Data Method with Separate Metadata

Request:

curl --request POST \
  --url https://demo.hykucommons.org/sword/collections/example-admin-set-id-12345/works/ \
  --header 'In-Progress: false' \
  --header 'On-Behalf-Of: admin@example.com' \
  --header 'Hyrax-Work-Model: Etd' \
  --header 'Api-key: example-key-12345' \
  -F metadata=@metadata.xml \
  -F payload=@testPackage.zip

c. Form Data Method with Combined Package

Request:

curl --request POST \
  --url https://demo.hykucommons.org/sword/collections/example-admin-set-id-12345/works/ \
  --header 'In-Progress: false' \
  --header 'On-Behalf-Of: admin@example.com' \
  --header 'Hyrax-Work-Model: Etd' \
  --header 'Api-key: example-key-12345' \
  -F payload=@testPackage.zip

5. BagIt Package Support

The API supports BagIt-formatted packages:

Request:

curl --request POST \
  --url https://demo.hykucommons.org/sword/collections/example-admin-set-id-12345/works/ \
  --header 'Content-Disposition: attachment; filename=testPackage1InBagit.zip' \
  --header 'Content-MD5: example-md5-12345' \
  --header 'Content-Type: application/zip' \
  --header 'Packaging: http://purl.org/net/sword/package/BagIt' \
  --header 'Hyrax-Work-Model: Etd' \
  --header 'Api-key: example-key-12345' \
  --data-binary @testPackageInBagit.zip

6. Retrieve Work Information

Request:

curl --request GET \
  --url https://demo.hykucommons.org/sword/collections/default/works/example-work-id-12345 \
  --header 'Api-key: example-key-12345'

7. File Operations

Get File Metadata

Request:

curl --request GET \
  --url https://demo.hykucommons.org/sword/collections/default/works/example-work-id-12345/file_sets/example-file-set-id-12345 \
  --header 'Api-key: example-key-12345'

Add File to Existing Work

Request:

curl --request POST \
  --url https://demo.hykucommons.org/sword/collections/default/works/example-work-id-12345/file_sets/ \
  --header 'Content-Disposition: attachment; filename=example.pdf' \
  --header 'Content-MD5: example-md5-12345' \
  --header 'Content-Type: application/pdf' \
  --header 'In-Progress: false' \
  --header 'On-Behalf-Of: admin@example.com' \
  --header 'Packaging: http://purl.org/net/sword/package/Binary' \
  --header 'Api-key: example-key-12345' \
  --data-binary @example.pdf

8. Update Operations

Update Work Metadata

Request:

curl --request PUT \
  --url https://demo.hykucommons.org/sword/collections/default/works/example-work-id-12345/ \
  --header 'Content-Disposition: attachment; filename=metadata.xml' \
  --header 'Content-Type: application/xml' \
  --header 'Packaging: application/atom+xml;type=entry' \
  --header 'Api-key: example-key-12345' \
  --data-binary @dc.xml

Update File Metadata

Request:

curl --request PUT \
  --url https://demo.hykucommons.org/sword/collections/default/works/example-work-id-12345/file_sets/example-file-set-id-12345 \
  --header 'Content-Disposition: attachment; filename=metadata.xml' \
  --header 'Content-Type: application/xml' \
  --header 'Packaging: application/atom+xml;type=entry' \
  --header 'Api-key: example-key-12345' \
  --data-binary @dc.xml

Package Formats

SimpleZip

Basic ZIP file containing files and optional metadata.xml:

package.zip
├── file1.pdf
├── file2.jpg
└── metadata.xml (optional)

BagIt

Standardized format for digital preservation:

bagit.zip
├── bag-info.txt
├── bagit.txt
├── manifest-md5.txt
├── data/
│   ├── file1.pdf
│   ├── file2.jpg
│   └── metadata/
│       └── metadata.xml
└── tagmanifest-md5.txt

Binary

Single file upload without packaging. Use header:

Packaging: http://purl.org/net/sword/package/Binary

Testing

A set of test files is available for validating your implementation: [swordv2_test_files.zip](https://github.com/scientist-softserv/palni-palci/files/15228815/swordv2_test_files.zip)

Example XML

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <title>Test Record</title>
  <creator>Hyku User</creator>
  <subject>Sword</subject>
  <subject>Implementation</subject>
  <description>This is a test dc record to test</description>
  <publisher>PALNI-PALCI</publisher>
  <contributor>Notch8</contributor>
  <created>29/05/2018</created>
  <source>https://www.hykucommons.org/</source>
  <language>English</language>
  <rights_statement>http://rightsstatements.org/vocab/InC/1.0/</rights_statement>
  <resource_type>Article</resource_type>
  <keyword>Test</keyword>
  <keyword>Another</keyword>
  <visibility>lease</visibility>
  <visibility_during_lease>authenticated</visibility_during_lease>
  <lease_expiration_date>2024-05-31</lease_expiration_date>
  <visibility_after_lease>restricted</visibility_after_lease>
  <!-- if no admin set id is specified, it will fallback to the Default Admin Set -->
  <admin_set_id>some-admin-set-id</admin_set_id>
</metadata>

Error Responses

The API uses standard SWORD V2 error responses:

Error HTTP Code Description
ErrorContent 415 Unsupported media type
ErrorChecksumMismatch 412 MD5 checksum mismatch
ErrorBadRequest 400 Malformed request
TargetOwnerUnknown 403 Unknown On-Behalf-Of user
MediationNotAllowed 412 Mediation not permitted
MethodNotAllowed 405 HTTP method not supported
MaxUploadSizeExceeded 413 File too large
ErrorUnprocessableEntity 422 Cannot process entity

Example error response:

<?xml version="1.0"?>
<error xmlns="http://purl.org/net/sword/error/">
  <title>Bad Request</title>
  <summary>Title is required</summary>
  <sword:treatment>processing failed</sword:treatment>
  <generator uri="https://demo.hykucommons.org/" version="2.0"/>
</error>

Acknowledgments

This implementation is based on the original WillowSword gem created by Cottage Labs [CottageLabs/willow_sword](https://github.com/CottageLabs/willow_sword). The fork was necessary to modernize the gem for compatibility with Hyrax's Valkyrie resources, moving away from the previous ActiveFedora implementation.