Skip to content

Instantly share code, notes, and snippets.

@blakejakopovic
Last active May 20, 2023 10:27
Show Gist options
  • Save blakejakopovic/eb82a2e417fd0846f2afcfc380988520 to your computer and use it in GitHub Desktop.
Save blakejakopovic/eb82a2e417fd0846f2afcfc380988520 to your computer and use it in GitHub Desktop.
NIP-YY - Nostr Service Definition

NIP-YY

Nostr Service Definition

draft optional author:wakoinc

A standardised service definition event allowing services to broadcast services they provide, and client apps to impliment support for a service type that is inter-changable

Motivation

Nostr is an ecosystem for apps and services built on a common layer. If we can define services using a common definition model, we can allow better user control and choice of services, and reduce implementation costs for adding new services for client apps. This MVP1 is focused on REST/HTTP endpoints.

This will allow

  • Client applications to add support for a service type, and users to select interchangable providers
  • Service providers to optionally advertise paid services (that may require auth)
  • Users to compare and pick the best value provider based on their needs

Note: This NIP has been written to ignore commercials and price information, as it's a separate concern.

Example use-cases

  • File hosting
  • Premium relays
  • CDNs
  • Translation services
  • NIP-05 providers

Examples

Nostr Event

{
  "kind": 30YYY,
  "tags": [],
  "content": <services JSON array>,
  ...other fields

nostrBuild File Upload Service

{
  "service_type": "file_upload",
  "service_name": "nostrBuild media hosting",
  "auth_methods": [],
  "endpoint": "https://nostr.build/api/upload/ios.php",
  "Inputs": {
    "fileToUpload": "file"
  },
  "headers": {
    "accept": "application/json"
  },
  "validation" : {
    "fileToUpload": {
      "content_types": ["image/jpeg","image/gif","image/png","image/wepb","video/mp4"],
      "max_size_bytes": 26214400,
      "accept_multiple": false,
      "auth_required": false
    }
  }
  "Response": {
    "Success": "@",
    "Error": null,
    "Result": "@"
  }
}

nostrimg File Upload Service

{
  "service_type": "file_upload",
  "service_name": "nostrimg media hosting",
  "auth_methods": [],
  "endpoint": "https://nostrimg.com/api/upload",
  "inputs": {
    "image": "file"
  },
  "headers": {
    "accept": "application/json"
  },
  "validation" : {
    "fileToUpload": {
      "content_types": ["image/jpeg","image/gif","image/png","image/wepb"],
      "max_size_bytes": 26214400,
      "accept_multiple": false,
      "auth_required": false
    }
  }
  "Response": {
    "Success": "success == `true` && status == `200`",
    "Error": "success != `true`",
    "Result": "data.link"
  }
}

DeepL Free translation Service

{
  "service_type": "text-translation",
  "service_name": "DeepL Free translation",
  "auth_methods": ["API_KEY"],
  "auth_required": true,
  "endpoint": "https://api-free.deepl.com/v2/translate",
  "inputs": {
    "text": "text",
    "source_lang": "text",
    "target_lang": "text",
  },
  "headers": {
    "accept": "application/json",
    "DeepL-Auth-Key": "${API_KEY}"
  },
  "validation" : {
    "text": {
      "max-length": 2048
    },
    "source_lang": {
      "values": ["$ISO 639-1"],
      "transforms": ["uppercase"]
    },
    "target_lang": {
      "values": ["$ISO 639-1"],
      "transforms": ["uppercase"]
    },
  }
  "Response": {
    "Success": null,
    "Error": null,
    "Result": "@[0].text"
  }
}

DeepL Pro translation Service

{
  "service_type": "text-translation",
  "service_name": "DeepL Pro translation",
  "auth_methods": ["API_KEY"],
  "auth_required": true,
  "endpoint": "https://api.deepl.com/v2/translate",
  "inputs": {
    "text": "text",
    "source_lang": "text",
    "target_lang": "text",
  },
  "headers": {
    "accept": "application/json",
    "DeepL-Auth-Key": "${API_KEY}"
  },
  "validation" : {
    "text": {
      "max-length": 10240
    },
    "source_lang": {
      "values": ["BG","ZH","CS","DA","NL","EN","ET","FI","FR","DE","EL","HU","ID","IT","JA","KO","LV","LT","NO","PL","PT","RO","RU","SK","SL","ES","SV","TR","UK"],
      "transforms": ["uppercase"]
    },
    "target_lang": {
      "values": ["BG","ZH","CS","DA","NL","EN","ET","FI","FR","DE","EL","HU","ID","IT","JA","KO","LV","LT","NO","PL","PT","RO","RU","SK","SL","ES","SV","TR","UK"],
      "transforms": ["uppercase"]
    },
  }
  "Response": {
    "Success": null,
    "Error": null,
    "Result": "@[0].text"
  }
}

nokyctranslate translation Service

{
  "service_type": "text-translation",
  "service_name": "nokyctranslate translation",
  "auth_methods": ["API_KEY"],
  "auth_required": true,
  "endpoint": "https://translate.nokyctranslate.com/translate", // POST
  "inputs": {
    "text": "text", // transform field to "q"
    "source_lang": "text", // transform field to "source"
    "target_lang": "text", // transform field to "target"
    "api_key": "$API_KEY",
  },
  "headers": {
    "accept": "application/json",
  },
  "validation" : {
    "text": {
      "max-length": 1024
    },
    "source": {
      "values": ["BG","ZH","CS","DA","NL","EN","ET","FI","FR","DE","EL","HU","ID","IT","JA","KO","LV","LT","NO","PL","PT","RO","RU","SK","SL","ES","SV","TR","UK"],
      "transforms": ["uppercase"]
    },
    "target": {
      "values": ["BG","ZH","CS","DA","NL","EN","ET","FI","FR","DE","EL","HU","ID","IT","JA","KO","LV","LT","NO","PL","PT","RO","RU","SK","SL","ES","SV","TR","UK"],
      "transforms": ["uppercase"]
    },
  }
  "Response": {
    "Success": null,
    "Error": null,
    "Result": "@.translatedText"
  }
}

nostr.wine filter Service

{
  "service_type": "relay",
  "service_name": "nostr.wine filter service",
  "auth_methods": ["RELAY_AUTH"],
  "auth_required": true,
  "endpoint": "wss://filter.nostr.wine",
  "inputs": {},
  "headers": {},
  "validation": {},
  "Response": {}
}

Areas that need work

  • How to verify/validate the service provider isn't an imposter
  • How to link service definitions to paid service offers
  • Defined list of auth types
  • How to allow AUTH for API keys (need dynamic inputs)
  • How to manage service API updates / lifecycle
  • We need to formalise the validation approach (syntax + transformations)
  • Can/do we need the ability to link status codes to success/fail?
  • How best to automate request API_KEY - as we likely don't need human interaction
  • Best way to query for services by provider, or by service type
  • Best way to query for service offers (membership or paid options)

Appendix

For response validation and data extraction, we're using JMESPath to help check for success or error, and also extract the response data

Prior work

https://github.com/michaelhall923/nostr-media-spec

@Semisol
Copy link

Semisol commented May 20, 2023

Yep - that was my thought too. However I wasn't sure which NIP-05 it should use? [email protected]

Browsers cannot validate it. services: {} entry in nostr.json or a nostr-services.json is better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment