Hydra hypermedia controls for .NET Web applications written in Nancy.
From Hydra hompage
Hydra simplifies the development of interoperable, hypermedia-driven Web APIs
Hydra does it by defining (still in production though) a wide variety of hypermedia controls, which allow the implementation of resilient API clients. This resilience is achieved by relying on runtime API documentation and not out-of-band information and human-readable API descriptions.
For more information please see it's specification page.
Argolis is a Super-Duper-Happy-Path towards documenting .NET web applications with Hydra. It struggles to be as simple as possible and have the least impact on your actual application logic:
- Provides out-of-the-box defaults and conventions
- Any default behaviour can be modified (thank you Strategy Pattern)
- Doesn't hijack responsibilities by using JsonLD.Entities and Nancy.Rdf packages
The name Argolis comes from the ancient (and modern) Greek province sometimes called The Argolid. Argolis is where the mythological monster Hydra lived. The monster's full name is Lernaean Hydra after the lake of Lerna, where it had it's lair.
And so the library exists in a specific state of trichotomy:
- The package is called Argolis, becasue Hydra was already taken 🚀
- The assemblies are called Lernaean.Hydra. after the mythical beast 🐉
- The base namespace is simply Hydra, because Lernaean is hard to spell 😉
To install add the Nuget package.
PM> Install-Package Argolis.Nancy
Currently only Nancy is supported, but the core library doesn't have a dependency and Web API or ServiceStack are definitely a possibility.
There are three steps requried to start using Agolis(.Nancy)
... and wire it up with Nancy.
public class HydraDocumentationSettings : IHydraDocumentationSettings
{
public string DocumentationPath
{
get { return "api"; }
}
public IriRef EntryPoint
{
get { return (IriRef)"http://localhost:61186/entrypoint"; }
}
}
public class ArgolisRegistrations : Registrations
{
public ArgolisRegistrations()
{
Register<IHydraDocumentationSettings>(new HydraDocumentationSettings());
}
}
This will set up the hydra:entryPoint
link and the
route used to serve API Documentation.
This interface is used to discover Type
s, which should be used to produce SupportedClasses exposed by the API.
There is an abstract class AssemblyAnnotatedTypeSelector
, which will look for types annotated with [SupportedClass]
in given assemblies.
public class AssembliesToScanForSupportedTypes : AssemblyAnnotatedTypeSelector
{
protected override IEnumerable<Assembly> Assemblies
{
get { yield return typeof (Issue).Assembly; }
}
}
[SupportedClass("http://example.api/o#Issue")]
[Description("An issue reported by our users")]
public class Issue : IssueBase
{
public string Id { get; set; }
[JsonProperty("titel")]
public string Title { get; set; }
public string Content { get; set; }
[Description("The number of people who liked this issue")]
public int LikesCount { get; private set; }
public bool IsResolved { get; set; }
public User Submitter { get; set; }
[Range("http://example.api/o#project")]
public string ProjectId { get; set; }
}
By default the only mandatory part is the [SupportedClass]
attribute.
Requesting the configured route will return the hydra:ApiDocumentation
(excerpt).
curl http://localhost:61186/api -H Accept:application/ld+json
{
"@context": {
// ...
},
"@id": "http://localhost:61186/api",
"@type": "ApiDocumentation",
"entrypoint": "http://localhost:61186/entrypoint",
"supportedClass": [
{
"@id": "http://example.api/o#Issue",
"@type": "Class",
"description": "An issue reported by our users",
"supportedProperty": [
{
"@type": "SupportedProperty",
"description": "The title property",
"property": {
"@id": "http://example.api/o#Issue/titel",
"@type": "rdf:Property",
"range": "xsd:string"
},
"readable": true,
"required": false,
"title": "title",
"writeable": true
},
{
"@type": "SupportedProperty",
"description": "The number of people who liked this issue",
"property": {
"@id": "http://example.api/o#Issue/likesCount",
"@type": "rdf:Property",
"range": "xsd:int"
},
"readable": true,
"required": false,
"title": "likesCount",
"writeable": false
},
{
"@type": "SupportedProperty",
"description": "The dateCreated property",
"property": {
"@id": "http://example.api/o#Issue/dateCreated",
"@type": "rdf:Property",
"range": "xsd:dateTime"
},
"readable": true,
"required": false,
"title": "dateCreated",
"writeable": false
}
],
"title": "Issue"
}
]
}
And any requested resource will include a Link
header to the Api Documentation
HTTP/1.1 200 OK
Link: <http://localhost:61186/api>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"