npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

api-tuner

v0.6.1

Published

**API** **T**ests **U**sing **n3** **R**ules

Readme

🎛️ API Tun3r 🎛️

API Tests Using n3 Rules

Prerequisites

  • SWI Prolog

    Follow platform-specific instructions to install locally oor in a docker image.

    To run api-tuner in GitHub workflow, you add this action to your jobs:

    - uses: fabasoad/setup-prolog-action@v1
  • curl 7.83+

Installation

npm i api-tuner

Usage

> api-tuner --help
Usage: api-tuner [options] <path>...

Options:
  --lib <path>       Specify rules to include in all tests. Can be used multiple times. Make sure to surround globs in quotes to prevent expansion.
  --silent           Less output
  --debug            Enable debug output
  --raw              Output raw results from eye
  --base-iri <iri>   Specify the base IRI for parsing the test case files
  --version          Show version information
  --help             Show this help message

Example

Create a test case file test.n3:

# test.n3
PREFIX earl: <http://www.w3.org/ns/earl#>
PREFIX tuner: <https://api-tuner.described.at/>
prefix resource: <https://api-tuner.described.at/resource#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX string: <http://www.w3.org/2000/10/swap/string#>

<#getExampleDotCom>
  a earl:TestCase ;
  rdfs:label "Simple GET test" ;
  tuner:formula {
    # Execute the request and capture its response
    ( <http://localhost:1080/example.com> ?res ) resource:getIn [] .

    # Check the response status code and content type
    ?res tuner:http_code 200 ;
      tuner:header ( "content-type" "text/html" ) ;
    .

    # Check the body contains the work "Example"
    ?res tuner:body ?body .
    ?body string:contains "Example Domain" .
  } ;
.

Execute the test case:

api-tuner test.n3

More examples

See the Documentation section below for more examples and detailed documentation of the N3 rules.

Documentation

This section describes the N3 rules and vocabulary used by api-tuner for defining and executing API tests.

Namespaces

Commonly used prefixes in api-tuner tests:

PREFIX tuner: <https://api-tuner.described.at/>
PREFIX resource: <https://api-tuner.described.at/resource#>
PREFIX earl: <http://www.w3.org/ns/earl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX log: <http://www.w3.org/2000/10/swap/log#>
PREFIX string: <http://www.w3.org/2000/10/swap/string#>

Defining a Test Case

A test case is defined as an earl:TestCase. The core logic of the test resides in tuner:formula.

<#myTest>
  a earl:TestCase ;
  rdfs:label "Description of my test" ;
  tuner:formula {
    # Test logic goes here
  } .

If the formula evaluates to true (all statements inside match), the test is considered earl:passed.

HTTP Requests

Request Object

You can define a detailed request using the tuner:Request class.

<#test> tuner:request [
  a tuner:Request ;
  tuner:method "POST" ;
  tuner:url <http://example.com/api> ;
  tuner:header ( "Accept" "application/json" ) ;
  tuner:query ( "verbose" "true" ) ;
  tuner:body { <#s> <#p> <#o> }
] .

To execute the request and get a response:

<#test> tuner:request ?req .
?req tuner:response ?res .

Simplified Helpers

The resource: namespace provides shortcuts for common HTTP methods. These helpers automatically assert a 200 OK response status unless used in a way that captures the response for further assertions.

  • ( <url> ?res ) resource:getIn []
  • ( <url> ?body ?res ) resource:postIn []
  • ( <url> ?res ) resource:postIn [] (no body)
  • ( <url> ?body ?res ) resource:putIn []

Example:

( <http://example.com> ?res ) resource:getIn [] .

Request Bodies

api-tuner supports different types of request bodies:

  1. Inline RDF: Uses an N3 formula. It is serialized as Turtle and sent with Content-Type: text/turtle.
    tuner:body { <#s> <#p> <#o> }
  2. File Reference: Sends the contents of a local file.
    tuner:body <file:data.json>
  3. Multipart Form:
    tuner:body [
      tuner:form ( "field1" "value1" ) ;
      tuner:form ( "fileField" <file:photo.jpg> "image/jpeg" ) ;
    ]

Query Parameters

Query parameters can be added to a request using tuner:query.

?req tuner:query ( "name" "value" ) .

Shell Variables

Values used in request URL, headers and query params are resolved from the shell environment.

<#test> tuner:request [
  a tuner:Request ;
  tuner:url <http://example.com/api/$PATH> ;
  tuner:header ( "X-Api-Key" "$API_KEY" ) ;
  tuner:query ( "q" "$QUERY" ) ;
] .

Assertions

Assertions are performed on the tuner:Response object (usually captured in a variable like ?res).

Status Code

Assert the HTTP status code:

?res tuner:http_code 200 .

Headers

Assert the presence and value of an HTTP header. Header names are case-insensitive.

  • Exact match:
    ?res tuner:header ( "Content-Type" "application/json" ) .
  • Regex match:
    ?res tuner:header ( "Content-Type" "application/.*" string:matches ) .

Body

  • Raw body string:

    ?res tuner:body ?body .
    ?body string:contains "Expected Text" .
  • RDF Semantics: If the response is RDF, you can use log:includes to check its content.

    ?res tuner:body ?body.
    ?body log:includes { <#s> <#p> <#o> } .

    ⚠️ Be careful when using ?res!log:includes resource path shorthand which will not work inside tuner:formula. Please refer to this discussion.

  • JSON Path: If the response is JSON, you can use tuner:jsonPath to assert values within the body.

    # Exact match
    ?res tuner:jsonPath ( "$.foo" "bar" ) .
    # Custom assertion (e.g. regex, contains, math)
    ?res tuner:jsonPath ( "$.baz" "42" string:contains ) .

    ⚠️ Note that unlike RDF assersion, JSON Path assertions are used on the response itself, without using tuner:body.

Generic Assertions

Use tuner:assertThat to fail a test with a custom message if a condition is not met.

{ ?value math:greaterThan 10 }!tuner:assertThat "Value should be greater than 10" .

Utility Rules

Logging

Print messages to the console during test execution (depending on log level).

  • ?message^tuner:info: Prints an INFO message.
  • ?message^tuner:trace: Prints a DEBUG message.

Example:

"Starting request"^tuner:info .

File Operations

  • () file:temp ?path: Generates a temporary file path.
  • ?path file:rm ?any: Deletes a file.
  • ?relative file:libPath ?absolute: Resolves a path relative to the api-tuner library.

Debugging

Setting the --debug flag will print verbose response information. The --raw flag will print the raw triples produced by the n3 rules.

Additionally, you can inspect the raw response files, which are written to the system's temp directory. The are prefixed with api-tuner. Thus, you can list them with ls -l "${TMPDIR:-/tmp}"/api-tuner*, or upload to CI artifacts, as shown in the GitHub Workflow step example below.

- run: npx api-tuner ...
  env:
    TMPDIR: ${{ runner.temp }}
- if: failure()
  name: upload api-tuner response data
  uses: actions/upload-artifact@v7
  with:
    name: api-tuner-debug
    path: '${{ runner.temp }}/api-tuner*'