1
0
mirror of https://github.com/oceanprotocol/docs.git synced 2024-11-26 19:49:26 +01:00

Merge pull request #72 from oceanprotocol/feature/api-docs

API docs for Aquarius & Brizo
This commit is contained in:
Matthias Kretschmann 2018-12-04 15:53:36 +01:00 committed by GitHub
commit 1c31fa58e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1554 additions and 104 deletions

View File

@ -2,7 +2,7 @@
<h1 align="center">docs</h1> <h1 align="center">docs</h1>
> 🐍 Ocean Protocol's official documentation. > 🐍 Ocean Protocol's official documentation. https://docs.oceanprotocol.com
[![Build Status](https://travis-ci.com/oceanprotocol/docs.svg?token=3psqw6c8KMDqfdGQ2x6d&branch=master)](https://travis-ci.com/oceanprotocol/docs) [![Build Status](https://travis-ci.com/oceanprotocol/docs.svg?token=3psqw6c8KMDqfdGQ2x6d&branch=master)](https://travis-ci.com/oceanprotocol/docs)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-7b1173.svg?style=flat-square)](https://github.com/prettier/prettier) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-7b1173.svg?style=flat-square)](https://github.com/prettier/prettier)
@ -27,6 +27,9 @@
- [Repositories](#repositories) - [Repositories](#repositories)
- [Add Links to a Repository](#add-links-to-a-repository) - [Add Links to a Repository](#add-links-to-a-repository)
- [Release Versions](#release-versions) - [Release Versions](#release-versions)
- [API & Library References](#api--library-references)
- [Swagger specs](#swagger-specs)
- [TypeDoc specs](#typedoc-specs)
- [Development](#development) - [Development](#development)
- [Using npm](#using-npm) - [Using npm](#using-npm)
- [Using Docker](#using-docker) - [Using Docker](#using-docker)
@ -186,6 +189,33 @@ The GitHub link is automatically added for every repository and will always be d
The displayed version number is based on the tag name of the latest release for a given repository. That means only GitHub releases will trigger a version number update, creating a new Git tag alone is not sufficient. The displayed version number is based on the tag name of the latest release for a given repository. That means only GitHub releases will trigger a version number update, creating a new Git tag alone is not sufficient.
### API & Library References
You can add more Markdown documents under `/content/references/`, link to them from the [`/data/sidebars/references.yml`](./data/sidebars/references.yml), and they will appear just like in all the other sections.
But the actual reference pages in this section are constructed from data files during site build (as defined in [`gatsby-node.js`](./gatsby-node.js)) with their own little rules. Generally, you can't edit their content within this site, you have to go to the respective repository and edit the documentation strings living with the source code.
The sidebar for those generated reference pages will automatically switch to include the table of contents of those pages so no need to define additional links in the [`/data/sidebars/references.yml`](./data/sidebars/references.yml) file for them.
#### Swagger specs
Reference pages based on Swagger specs are sourced from a Swagger spec `json` file, at the moment they simply live as manual copies under `/data/`:
- [`aquarius.json`](./data/aquarius.json)
- [`brizo.json`](./data/brizo.json)
There's no automation setup around updating those files so [until this is setup](https://github.com/oceanprotocol/docs/issues/74), they need to be manually updated with copy & paste, like they did in the middle ages. You can copy them from a running instance of Aquarius or Brizo which will expose those spec files, e.g. under `localhost:5000/spec` for Aquarius and `localhost:8030/spec` for Brizo.
For more information about stylistic issues, take a look at the section in the test page:
- [Swagger spec references](https://docs.oceanprotocol.com/test#swagger-spec-references)
#### TypeDoc specs
Reference pages based on generated `json` file from TypeDoc.
_Coming soon... see [#45](https://github.com/oceanprotocol/docs/issues/45)_
## Development ## Development
The site is a React app built with [Gatsby](https://www.gatsbyjs.org). The site is a React app built with [Gatsby](https://www.gatsbyjs.org).
@ -198,8 +228,8 @@ This Git repo has [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Subm
git clone --recurse-submodules git@github.com:oceanprotocol/docs.git git clone --recurse-submodules git@github.com:oceanprotocol/docs.git
``` ```
1. Don't edit anything in the submodules (i.e. in `external/`). Instead, edit it over in the other Git repository and merge your changes over there. 2. Don't edit anything in the submodules (i.e. in `external/`). Instead, edit it over in the other Git repository and merge your changes over there.
1. Get all the submodules up-to-date using: 3. Get all the submodules up-to-date using:
```bash ```bash
git submodule update --remote --recursive git submodule update --remote --recursive
@ -207,7 +237,7 @@ This Git repo has [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Subm
That will get each submodule up-to-date with the HEAD commit of some branch in a remote repository. Which branch? That's set in the `.gitmodules` file. You can check the current commit hashes of all the submodules using `git submodule status` That will get each submodule up-to-date with the HEAD commit of some branch in a remote repository. Which branch? That's set in the `.gitmodules` file. You can check the current commit hashes of all the submodules using `git submodule status`
1. Before doing any `git checkout ...` or other normal Git operations, do this: 4. Before doing any `git checkout ...` or other normal Git operations, do this:
```bash ```bash
git config --global submodule.recurse true git config --global submodule.recurse true

View File

@ -31,6 +31,10 @@ module.exports = {
{ {
from: '/tutorials/', from: '/tutorials/',
to: '/tutorials/introduction/' to: '/tutorials/introduction/'
},
{
from: '/references/',
to: '/references/introduction/'
} }
] ]
} }

View File

@ -0,0 +1,19 @@
---
title: API & Library References
description: All the references for Ocean Protocol components.
---
**Heads Up! This reference section is in heavy development and updated as we integrate data from various code reference tools into this site.**
The following components expose a consumable REST API which are documented on this site:
<repo name="aquarius"></repo>
<repo name="brizo"></repo>
Those are sourced from their respective Swagger specs. On this site you can't execute the documented API calls yet. If you need this, you can run a component's local Swagger UI as outlined in the repository instructions on GitHub.
References of all the functions and methods used in our libraries are not yet integrated here. For now, have a look at the respective repos for more infos:
<repo name="squid-js"></repo>
<repo name="squid-py"></repo>
<repo name="squid-java"></repo>

View File

@ -366,3 +366,14 @@ GITHUB-EMBED https://github.com/oceanprotocol/squid-js/blob/develop/src/keeper/W
Resulting in: Resulting in:
GITHUB-EMBED https://github.com/oceanprotocol/squid-js/blob/develop/src/keeper/Web3Provider.ts js GITHUB-EMBED GITHUB-EMBED https://github.com/oceanprotocol/squid-js/blob/develop/src/keeper/Web3Provider.ts js GITHUB-EMBED
## Swagger spec references
Many Swagger fields like the description (`info.description`) are rendered through Markdown so you can write actual Markdown in those fields.
- [Aquarius API reference](/references/aquarius/)
- [Brizo API reference](/references/brizo/)
For a complete overview of everything supported by Swagger and implemented in this site, take a look at the hidden Pet Store example:
- [Pet Store Example](/references/pet-store/)

532
data/aquarius.json Normal file
View File

@ -0,0 +1,532 @@
{
"basePath":"/api/v1/aquarius",
"definitions":{
},
"host":"myfancyaquarius.com",
"info":{
"description":"Aquarius provides an off-chain database store for metadata about data assets. When running with our Docker images, it is exposed under `http://localhost:5000`.",
"title":"Aquarius",
"version":"0.1.4"
},
"paths":{
"/api/v1/aquarius/assets":{
"get":{
"description":"",
"responses":{
"200":{
"description":"successful action"
}
},
"summary":"Get all asset IDs.",
"tags":[
"ddo"
]
}
},
"/api/v1/aquarius/assets/ddo":{
"get":{
"description":"",
"responses":{
"200":{
"description":"successful action"
}
},
"summary":"Get DDO of all assets.",
"tags":[
"ddo"
]
},
"post":{
"consumes":[
"application/json"
],
"description":"",
"parameters":[
{
"description":"DDO of the asset.",
"in":"body",
"name":"body",
"required":true,
"schema":{
"properties":{
"@context":{
"description":null,
"example":"https://w3id.org/future-method/v1",
"type":"string"
},
"authentication":{
"description":"List of authentication mechanisms.",
"example":[
{
"type":"RsaSignatureAuthentication2018"
},
{
"publicKey":"did:op:123456789abcdefghi#keys-1"
}
],
"type":"array"
},
"id":{
"description":"ID of the asset.",
"example":"did:op:123456789abcdefghi",
"type":"string"
},
"publicKey":{
"description":"List of public keys.",
"example":[
{
"id":"did:op:123456789abcdefghi#keys-1"
},
{
"type":"Ed25519VerificationKey2018"
},
{
"owner":"did:op:123456789abcdefghi"
},
{
"publicKeyBase58":"H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}
],
"type":"array"
},
"service":{
"description":"List of services.",
"example":[
{
"serviceEndpoint":"http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
"type":"Consume"
},
{
"serviceEndpoint":"http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}",
"type":"Compute"
},
{
"metadata":{
"additionalInformation":{
"structuredMarkup":[
{
"mediaType":"application/ld+json",
"uri":"http://skos.um.es/unescothes/C01194/jsonld"
},
{
"mediaType":"text/turtle",
"uri":"http://skos.um.es/unescothes/C01194/turtle"
}
],
"updateFrecuency":"yearly"
},
"base":{
"author":"Met Office",
"compression":"zip",
"contentType":"text/csv",
"contentUrls":[
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip"
],
"copyrightHolder":"Met Office",
"dateCreated":"2012-10-10T17:00:000Z",
"description":"Weather information of UK including temperature and humidity",
"encoding":"UTF-8",
"inLanguage":"en",
"license":"CC-BY",
"links":[
{
"sample1":"http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/"
},
{
"sample2":"http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-averages-25km/"
},
{
"fieldsDescription":"http://data.ceda.ac.uk/badc/ukcp09/"
}
],
"name":"UK Weather information 2011",
"price":10,
"size":"3.1gb",
"tags":"weather, uk, 2011, temperature, humidity",
"type":"dataset",
"workExample":"423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68"
},
"curation":{
"numVotes":123,
"rating":0.93,
"schema":"Binary Votting"
}
},
"serviceEndpoint":"http://myaquarius.org/api/v1/provider/assets/metadata/{did}",
"type":"Metadata"
}
],
"type":"array"
}
},
"required":[
"@context",
"id",
"publicKey",
"authentication",
"service"
],
"type":"object"
}
}
],
"responses":{
"201":{
"description":"Asset successfully registered."
},
"400":{
"description":"One of the required attributes is missing."
},
"404":{
"description":"Invalid asset data."
},
"500":{
"description":"Error"
}
},
"summary":"Register DDO of a new asset",
"tags":[
"ddo"
]
}
},
"/api/v1/aquarius/assets/ddo/query":{
"get":{
"description":"",
"parameters":[
{
"description":"ID of the asset.",
"in":"query",
"name":"text",
"required":true,
"type":"string"
},
{
"description":"Key or list of keys to sort the result",
"example":{
"value":1
},
"in":"query",
"name":"sort",
"type":"object"
},
{
"description":"Number of records per page",
"example":100,
"in":"query",
"name":"offset",
"type":"int"
},
{
"description":"Page showed",
"example":0,
"in":"query",
"name":"page",
"type":"int"
}
],
"responses":{
"200":{
"description":"successful action"
}
},
"summary":"Get a list of DDOs that match with the given text.",
"tags":[
"ddo"
]
},
"post":{
"consumes":[
"application/json"
],
"description":"",
"parameters":[
{
"description":"Asset metadata.",
"in":"body",
"name":"body",
"required":true,
"schema":{
"properties":{
"offset":{
"description":"Number of records per page",
"example":100,
"type":"int"
},
"page":{
"description":"Page showed",
"example":0,
"type":"int"
},
"query":{
"description":"Query to realize",
"example":{
"value":1
},
"type":"string"
},
"sort":{
"description":"Key or list of keys to sort the result",
"example":{
"value":1
},
"type":"object"
}
},
"type":"object"
}
}
],
"responses":{
"200":{
"description":"successful action"
}
},
"summary":"Get a list of DDOs that match with the executed query.",
"tags":[
"ddo"
]
}
},
"/api/v1/aquarius/assets/ddo/{did}":{
"put":{
"consumes":[
"application/json"
],
"description":"",
"parameters":[
{
"description":"DDO of the asset.",
"in":"body",
"name":"body",
"required":true,
"schema":{
"properties":{
"@context":{
"description":null,
"example":"https://w3id.org/future-method/v1",
"type":"string"
},
"authentication":{
"description":"List of authentication mechanisms.",
"example":[
{
"type":"RsaSignatureAuthentication2018"
},
{
"publicKey":"did:op:123456789abcdefghi#keys-1"
}
],
"type":"array"
},
"id":{
"description":"ID of the asset.",
"example":"did:op:123456789abcdefghi",
"type":"string"
},
"publicKey":{
"description":"List of public keys.",
"example":[
{
"id":"did:op:123456789abcdefghi#keys-1"
},
{
"type":"Ed25519VerificationKey2018"
},
{
"owner":"did:op:123456789abcdefghi"
},
{
"publicKeyBase58":"H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}
],
"type":"array"
},
"service":{
"description":"List of services.",
"example":[
{
"serviceEndpoint":"http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
"type":"Consume"
},
{
"serviceEndpoint":"http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}",
"type":"Compute"
},
{
"metadata":{
"additionalInformation":{
"structuredMarkup":[
{
"mediaType":"application/ld+json",
"uri":"http://skos.um.es/unescothes/C01194/jsonld"
},
{
"mediaType":"text/turtle",
"uri":"http://skos.um.es/unescothes/C01194/turtle"
}
],
"updateFrecuency":"yearly"
},
"base":{
"author":"Met Office",
"compression":"zip",
"contentType":"text/csv",
"contentUrls":[
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip"
],
"copyrightHolder":"Met Office",
"dateCreated":"2012-10-10T17:00:000Z",
"description":"Weather information of UK including temperature and humidity",
"encoding":"UTF-8",
"inLanguage":"en",
"license":"CC-BY",
"links":[
{
"name":"Sample of Asset Data",
"type":"sample",
"url":"https://foo.com/sample.csv"
},
{
"AssetID":"4d517500da0acb0d65a716f61330969334630363ce4a6a9d39691026ac7908ea",
"name":"Data Format Definition",
"type":"format"
}
],
"name":"UK Weather information 2011",
"price":10,
"size":"3.1gb",
"tags":"weather, uk, 2011, temperature, humidity",
"type":"dataset",
"workExample":"423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68"
},
"curation":{
"numVotes":123,
"rating":0.93,
"schema":"Binary Voting"
}
},
"serviceEndpoint":"http://myaquarius.org/api/v1/aquarius/assets/metadata/{did}",
"type":"Metadata"
}
],
"type":"array"
}
},
"required":[
"@context",
"id",
"publicKey",
"authentication",
"service"
],
"type":"object"
}
}
],
"responses":{
"200":{
"description":"Asset successfully updated."
},
"201":{
"description":"Asset successfully registered."
},
"400":{
"description":"One of the required attributes is missing."
},
"404":{
"description":"Invalid asset data."
},
"500":{
"description":"Error"
}
},
"summary":"Update DDO of an existing asset",
"tags":[
"ddo"
]
}
},
"/api/v1/aquarius/assets/ddo/{id}":{
"delete":{
"description":"",
"parameters":[
{
"description":"ID of the asset.",
"in":"path",
"name":"id",
"required":true,
"type":"string"
}
],
"responses":{
"200":{
"description":"successfully deleted"
},
"404":{
"description":"This asset ID is not in OceanDB"
},
"500":{
"description":"Error"
}
},
"summary":"Retire metadata of an asset",
"tags":[
"ddo"
]
},
"get":{
"description":"",
"parameters":[
{
"description":"ID of the asset.",
"in":"path",
"name":"id",
"required":true,
"type":"string"
}
],
"responses":{
"200":{
"description":"successful operation"
},
"404":{
"description":"This asset ID is not in OceanDB"
}
},
"summary":"Get DDO of a particular asset.",
"tags":[
"ddo"
]
}
},
"/api/v1/aquarius/assets/metadata/{id}":{
"get":{
"description":"",
"parameters":[
{
"description":"ID of the asset.",
"in":"path",
"name":"id",
"required":true,
"type":"string"
}
],
"responses":{
"200":{
"description":"successful operation."
},
"404":{
"description":"This asset ID is not in OceanDB."
}
},
"summary":"Get metadata of a particular asset",
"tags":[
"metadata"
]
}
}
},
"swagger":"2.0"
}

200
data/brizo.json Normal file
View File

@ -0,0 +1,200 @@
{
"basePath":"/api/v1/brizo",
"definitions":{
},
"host":"myfancybrizo.com",
"info":{
"description":"Brizo is the technical component executed by Publishers allowing them to provide extended data services. When running with our Docker images, it is exposed under `http://localhost:8030`.",
"title":"Brizo",
"version":"0.1.2"
},
"paths":{
"/api/v1/brizo/services/access/initialize":{
"post":{
"consumes":[
"application/json"
],
"description":"",
"parameters":[
{
"description":"Service agreement initialization.",
"in":"body",
"name":"body",
"required":true,
"schema":{
"properties":{
"consumerAddress":{
"description":"Consumer address.",
"example":"0x00a329c0648769A73afAc7F9381E08FB43dBEA72",
"type":"string"
},
"did":{
"description":"Identifier of the asset registered in ocean.",
"example":"did:op:08a429b8529856d59867503f8056903a680935a76950bb9649785cc97869a43d",
"type":"string"
},
"serviceAgreementId":{
"description":"Identifier of the service agreement.",
"example":"bb23s87856d59867503f80a690357406857698570b964ac8dcc9d86da4ada010",
"type":"string"
},
"serviceDefinitionId":{
"description":"Identifier of the service definition.",
"example":"0",
"type":"string"
},
"signature":{
"description":"Signature",
"example":"cade376598342cdae231321a0097876aeda656a567a67c6767fd8710129a9dc1",
"type":"string"
}
},
"required":[
"did",
"serviceAgreementId",
"serviceDefinitionId",
"signature",
{
"consumerAddress":null
}
],
"type":"object"
}
}
],
"responses":{
"201":{
"description":"Service agreement successfully initialized."
},
"400":{
"description":"One of the required attributes is missing."
},
"404":{
"description":"Invalid signature."
},
"500":{
"description":"Error"
}
},
"summary":"Initialize the SLA between the publisher and the consumer.",
"tags":[
"services"
]
}
},
"/api/v1/brizo/services/compute":{
"post":{
"consumes":[
"application/json"
],
"description":"",
"parameters":[
{
"description":"Asset metadata.",
"in":"body",
"name":"body",
"required":true,
"schema":{
"properties":{
"algorithm_did":{
"description":"Identifier of the algorithm to execute",
"example":"0x0234242345",
"type":"string"
},
"asset_did":{
"description":"Identifier of the asset registered in Ocean",
"example":"0x0234242345",
"type":"string"
},
"consumer_wallet":{
"description":"Address of the wallet of the asset consumer. Ex. data-science...",
"example":"0x0234242345",
"type":"string"
},
"cpu":{
"description":"Number of CPUs to execute the algorithm.",
"example":1,
"type":"integer"
},
"docker_image":{
"description":"Docker image where the algorithm is going to be executed. Docker image must include all the libraries needed to run it.",
"example":"python:3.6-alpine",
"type":"string"
},
"memory":{
"description":"Ammout of memory in GB to run the algorithm",
"example":1.5,
"type":"number"
}
},
"required":[
"asset_did",
"algorithm_did",
"consumer_wallet"
],
"type":"object"
}
}
],
"responses":{
},
"summary":"Allows to execute an algorithm inside a Docker instance in the cloud. Requires the publisher of the assets to provide this service in the service agreement related with the requested `asset_did`.",
"tags":[
"services"
]
}
},
"/api/v1/brizo/services/consume":{
"get":{
"consumes":[
"application/json"
],
"description":"",
"parameters":[
{
"description":"The consumer address.",
"in":"query",
"name":"consumerAddress",
"required":true,
"type":"string"
},
{
"description":"The ID of the service agreement.",
"in":"query",
"name":"serviceAgreementId",
"required":true,
"type":"string"
},
{
"description":"This URL is only valid if Brizo acts as a proxy. Consumer can't download using the URL if it's not through Brizo.",
"in":"query",
"name":"url",
"required":true,
"type":"string"
}
],
"responses":{
"302":{
"description":"Redirect to valid asset url."
},
"400":{
"description":"One of the required attributes is missing."
},
"404":{
"description":"Invalid asset data."
},
"500":{
"description":"Error"
}
},
"summary":"Allows download of asset data file.",
"tags":[
"services"
]
}
}
},
"swagger":"2.0"
}

View File

@ -8,9 +8,13 @@
- name: aquarius - name: aquarius
links: links:
- name: API reference - name: API reference
url: https://github.com/oceanprotocol/aquarius/blob/develop/docs/for_api_users/API.md url: /references/aquarius/
- name: brizo - name: brizo
links:
- name: API reference
url: /references/brizo/
- name: pleuston - name: pleuston
- group: Libraries - group: Libraries

View File

@ -13,8 +13,7 @@
link: /tutorials/introduction/ link: /tutorials/introduction/
color: orange color: orange
- title: API References - title: API & Library References
#description: Get the API references for all relevant components. description: Get the references for REST APIs and library methods for all relevant components.
description: Coming soon. link: /references/introduction/
#link: /api/introduction/
color: green color: green

View File

@ -0,0 +1,19 @@
- group: Overview
items:
- title: API References
link: /references/introduction/
# - group: squid-js
# items:
# - title: API reference
# link: /api/squid-js/
- group: aquarius
items:
- title: API reference
link: /references/aquarius/
- group: brizo
items:
- title: API reference
link: /references/brizo/

View File

@ -131,7 +131,7 @@ module.exports = {
{ {
resolve: 'gatsby-plugin-sitemap', resolve: 'gatsby-plugin-sitemap',
options: { options: {
exclude: ['/test/'] exclude: ['/test/', '/references/petstore/']
} }
}, },
{ {

View File

@ -2,6 +2,7 @@
const path = require('path') const path = require('path')
const { createFilePath } = require('gatsby-source-filesystem') const { createFilePath } = require('gatsby-source-filesystem')
const Swagger = require('swagger-client')
const { redirects } = require('./config') const { redirects } = require('./config')
exports.onCreateNode = ({ node, getNode, actions }) => { exports.onCreateNode = ({ node, getNode, actions }) => {
@ -36,6 +37,26 @@ exports.onCreateNode = ({ node, getNode, actions }) => {
} }
} }
// https://github.com/swagger-api/swagger-js
const getSpec = async () => {
const spec = await Swagger(
'http://petstore.swagger.io/v2/swagger.json'
).then(client => {
return client.spec // The resolved spec
// client.originalSpec // In case you need it
// client.errors // Any resolver errors
// Tags interface
// client.apis.pet.addPet({id: 1, name: "bobby"}).then(...)
// TryItOut Executor, with the `spec` already provided
// client.execute({operationId: 'addPet', parameters: {id: 1, name: "bobby") }).then(...)
})
return spec
}
exports.createPages = ({ graphql, actions }) => { exports.createPages = ({ graphql, actions }) => {
const { createPage, createRedirect } = actions const { createPage, createRedirect } = actions
@ -43,7 +64,7 @@ exports.createPages = ({ graphql, actions }) => {
resolve( resolve(
graphql( graphql(
` `
{ query {
allMarkdownRemark( allMarkdownRemark(
filter: { fileAbsolutePath: { regex: "/content/" } } filter: { fileAbsolutePath: { regex: "/content/" } }
) { ) {
@ -79,9 +100,8 @@ exports.createPages = ({ graphql, actions }) => {
} }
} }
` `
).then(result => { ).then(async result => {
if (result.errors) { if (result.errors) {
/* eslint-disable-next-line no-console */
console.log(result.errors) console.log(result.errors)
reject(result.errors) reject(result.errors)
} }
@ -89,7 +109,9 @@ exports.createPages = ({ graphql, actions }) => {
const docTemplate = path.resolve('./src/templates/Doc.jsx') const docTemplate = path.resolve('./src/templates/Doc.jsx')
const posts = result.data.allMarkdownRemark.edges const posts = result.data.allMarkdownRemark.edges
//
// Create Doc pages // Create Doc pages
//
posts.forEach(post => { posts.forEach(post => {
createPage({ createPage({
path: `${post.node.fields.slug}`, path: `${post.node.fields.slug}`,
@ -101,7 +123,9 @@ exports.createPages = ({ graphql, actions }) => {
}) })
}) })
//
// Create pages from dev-ocean contents // Create pages from dev-ocean contents
//
const postsDevOcean = result.data.devOceanDocs.edges const postsDevOcean = result.data.devOceanDocs.edges
postsDevOcean postsDevOcean
@ -125,6 +149,54 @@ exports.createPages = ({ graphql, actions }) => {
}) })
}) })
//
// Create pages from swagger json files
//
const apiSwaggerTemplate = path.resolve(
'./src/templates/ApiSwagger.jsx'
)
const petStoreSlug = '/references/petstore/'
try {
const spec = await getSpec()
createPage({
path: petStoreSlug,
component: apiSwaggerTemplate,
context: {
slug: petStoreSlug,
api: spec
}
})
} catch (error) {
console.log(error)
}
const aquariusSpecs = require('./data/aquarius.json')
const aquariusSlug = '/references/aquarius/'
createPage({
path: aquariusSlug,
component: apiSwaggerTemplate,
context: {
slug: aquariusSlug,
api: aquariusSpecs
}
})
const brizoSpecs = require('./data/brizo.json')
const brizoSlug = '/references/brizo/'
createPage({
path: brizoSlug,
component: apiSwaggerTemplate,
context: {
slug: brizoSlug,
api: brizoSpecs
}
})
// //
// create redirects // create redirects
// //

View File

@ -59,7 +59,9 @@
"react-helmet": "^5.2.0", "react-helmet": "^5.2.0",
"rehype-react": "^3.1.0", "rehype-react": "^3.1.0",
"remark": "^10.0.1", "remark": "^10.0.1",
"remark-react": "^5.0.0" "remark-react": "^5.0.0",
"slugify": "^1.3.3",
"swagger-client": "^3.8.22"
}, },
"devDependencies": { "devDependencies": {
"@svgr/webpack": "^4.1.0", "@svgr/webpack": "^4.1.0",

View File

@ -4,31 +4,31 @@ import { ReactComponent as Pencil } from '../images/pencil.svg'
import styles from './DocFooter.module.scss' import styles from './DocFooter.module.scss'
import { githubContentPath, githubDevOceanPath } from '../../config' import { githubContentPath, githubDevOceanPath } from '../../config'
const DocFooter = ({ post }) => { const DocFooter = ({ post, url, externalName }) => {
const { sourceInstanceName } = post.parent
let path let path
let externalRepoName
if (post) {
const { sourceInstanceName } = post.parent
switch (sourceInstanceName) { switch (sourceInstanceName) {
case 'dev-ocean': case 'dev-ocean':
path = githubDevOceanPath path = githubDevOceanPath
externalRepoName = sourceInstanceName externalName = sourceInstanceName
break break
default: default:
path = githubContentPath path = githubContentPath
} }
url = `${path}/${post.parent.relativePath}`
}
return ( return (
<footer className={styles.footer}> <footer className={styles.footer}>
<a <a href={url} className={post && !post.html ? styles.active : null}>
href={`${path}/${post.parent.relativePath}`}
className={!post.html ? styles.active : null}
>
<Pencil /> Edit this page on GitHub <Pencil /> Edit this page on GitHub
{externalRepoName && ( {externalName && (
<span className={styles.externalRepoName}> <span className={styles.externalRepoName}>
{externalRepoName} {externalName}
</span> </span>
)} )}
</a> </a>
@ -37,7 +37,9 @@ const DocFooter = ({ post }) => {
} }
DocFooter.propTypes = { DocFooter.propTypes = {
post: PropTypes.object.isRequired post: PropTypes.object,
url: PropTypes.string,
externalName: PropTypes.string
} }
export default DocFooter export default DocFooter

View File

@ -4,7 +4,7 @@ import remark from 'remark'
import remarkReact from 'remark-react' import remarkReact from 'remark-react'
import styles from './DocHeader.module.scss' import styles from './DocHeader.module.scss'
const DocHeader = ({ title, description }) => { const DocHeader = ({ title, description, prepend }) => {
const descriptionHtml = const descriptionHtml =
description && description &&
remark() remark()
@ -13,7 +13,9 @@ const DocHeader = ({ title, description }) => {
return ( return (
<header className={styles.header}> <header className={styles.header}>
<h1 className={styles.title}>{title}</h1> <h1 className={styles.title}>
{title} {prepend && prepend}
</h1>
{description && ( {description && (
<div className={styles.lead}>{descriptionHtml}</div> <div className={styles.lead}>{descriptionHtml}</div>
)} )}
@ -23,7 +25,8 @@ const DocHeader = ({ title, description }) => {
DocHeader.propTypes = { DocHeader.propTypes = {
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
description: PropTypes.string description: PropTypes.string,
prepend: PropTypes.any
} }
export default DocHeader export default DocHeader

View File

@ -39,12 +39,7 @@ const Header = () => (
</Link> </Link>
<nav className={styles.headerMenu}> <nav className={styles.headerMenu}>
{sections {sections.map(({ node }) => (
.filter(
({ node }) =>
node.title !== 'API References'
)
.map(({ node }) => (
<Link <Link
key={node.title} key={node.title}
to={node.link} to={node.link}

View File

@ -22,6 +22,10 @@
:global(.tutorials) & { :global(.tutorials) & {
color: $orange; color: $orange;
} }
:global(.references) & {
color: $green;
}
} }
.rootLink { .rootLink {

View File

@ -7,7 +7,12 @@ const SidebarLink = ({ link, title, linkClasses }) => {
if (link) { if (link) {
if (link.match(/^\s?http(s?)/gi)) { if (link.match(/^\s?http(s?)/gi)) {
return ( return (
<a href={link} target="_blank" rel="noopener noreferrer"> <a
href={link}
className={linkClasses}
target="_blank"
rel="noopener noreferrer"
>
{title} {title}
</a> </a>
) )
@ -23,8 +28,21 @@ const SidebarLink = ({ link, title, linkClasses }) => {
} }
} }
const SidebarList = ({ items, location }) => ( SidebarLink.propTypes = {
<ul className={styles.list}> link: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
linkClasses: PropTypes.string
}
const SidebarList = ({ items, location, toc, tableOfContents }) => (
<div className={styles.list}>
{toc ? (
<div
className={styles.toc}
dangerouslySetInnerHTML={{ __html: tableOfContents }}
/>
) : (
<ul>
{items.map((item, j) => ( {items.map((item, j) => (
<li key={j}> <li key={j}>
<SidebarLink <SidebarLink
@ -39,33 +57,18 @@ const SidebarList = ({ items, location }) => (
</li> </li>
))} ))}
</ul> </ul>
)}
</div>
) )
export default class Sidebar extends Component { SidebarList.propTypes = {
static propTypes = { items: PropTypes.array.isRequired,
sidebar: PropTypes.string, location: PropTypes.object.isRequired,
location: PropTypes.object.isRequired toc: PropTypes.bool,
tableOfContents: PropTypes.string
} }
static defaultProps = { const SidebarGroupTitle = ({ group }) => (
location: { pathname: `/` }
}
render() {
const { sidebar, location } = this.props
const sidebarfile = sidebar
? require(`../../data/sidebars/${sidebar}.yml`) // eslint-disable-line
: []
if (!sidebarfile) {
return null
}
return (
<nav className={styles.sidebar}>
{sidebarfile.map((group, i) => (
<div key={i}>
<h4 className={styles.groupTitle}> <h4 className={styles.groupTitle}>
{group.items[0].link ? ( {group.items[0].link ? (
<SidebarLink <SidebarLink
@ -77,25 +80,84 @@ export default class Sidebar extends Component {
group.group group.group
)} )}
</h4> </h4>
)
SidebarGroupTitle.propTypes = {
group: PropTypes.object.isRequired
}
const SidebarGroup = ({ i, group, location, ...props }) => (
<>
<SidebarGroupTitle group={group} />
<SidebarList <SidebarList
key={i} key={i}
items={group.items} items={group.items}
location={location} location={location}
{...props}
/> />
</>
)
export default class Sidebar extends Component {
static propTypes = {
sidebar: PropTypes.string,
location: PropTypes.object.isRequired,
collapsed: PropTypes.bool,
toc: PropTypes.bool,
tableOfContents: PropTypes.string
}
static defaultProps = { location: { pathname: '/' } }
render() {
const {
sidebar,
location,
collapsed,
toc,
tableOfContents
} = this.props
if (sidebar) {
try {
var sidebarfile = require(`../../data/sidebars/${sidebar}.yml`) // eslint-disable-line
} catch (e) {
throw e
}
}
if (!sidebarfile) {
return null
}
return (
<nav className={styles.sidebar}>
{sidebarfile.map((group, i) => (
<div key={i}>
{collapsed ? (
group.items.some(
item => item.link === location.pathname
) ? (
<SidebarGroup
i={i}
group={group}
location={location}
toc={toc}
tableOfContents={tableOfContents}
/>
) : (
<SidebarGroupTitle group={group} />
)
) : (
<SidebarGroup
i={i}
group={group}
location={location}
/>
)}
</div> </div>
))} ))}
</nav> </nav>
) )
} }
} }
SidebarLink.propTypes = {
link: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
linkClasses: PropTypes.string
}
SidebarList.propTypes = {
items: PropTypes.array.isRequired,
location: PropTypes.object.isRequired
}

View File

@ -54,6 +54,10 @@
border-left: 1px solid $brand-grey-lighter; border-left: 1px solid $brand-grey-lighter;
margin-left: $spacer / 2; margin-left: $spacer / 2;
> ul {
padding-left: 0;
}
li { li {
display: block; display: block;
@ -63,7 +67,8 @@
} }
} }
.link { .link,
.toc a {
color: $brand-grey; color: $brand-grey;
display: inline-block; display: inline-block;
padding: $spacer / 6 $spacer / 2; padding: $spacer / 6 $spacer / 2;
@ -77,6 +82,21 @@
} }
} }
.toc {
ul {
padding-left: 0;
ul {
padding-left: $spacer / 2;
margin: 0;
}
}
li {
margin: 0;
}
}
.active { .active {
composes: link; composes: link;
color: $brand-purple; color: $brand-purple;

View File

@ -38,8 +38,6 @@
&:last-child { &:last-child {
flex-basis: 100%; flex-basis: 100%;
text-align: center; text-align: center;
opacity: .5;
pointer-events: none;
} }
} }

View File

@ -272,6 +272,14 @@ samp {
font-size: $font-size-small !important; font-size: $font-size-small !important;
border-radius: $border-radius !important; border-radius: $border-radius !important;
text-shadow: none !important; text-shadow: none !important;
h1 &,
h2 &,
h3 &,
h4 &,
h5 & {
font-size: inherit !important;
}
} }
:not(pre) > code { :not(pre) > code {

View File

@ -0,0 +1,321 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { graphql } from 'gatsby'
import Helmet from 'react-helmet'
import slugify from 'slugify'
import Layout from '../components/Layout'
import Content from '../components/Content'
import HeaderSection from '../components/HeaderSection'
import Sidebar from '../components/Sidebar'
import DocHeader from '../components/DocHeader'
import DocFooter from '../components/DocFooter'
import SEO from '../components/Seo'
import stylesDoc from './Doc.module.scss'
import styles from './ApiSwagger.module.scss'
const cleanKey = key => {
let keyCleaned = key
if (key.includes('aquarius')) {
keyCleaned = key.replace(/\/api\/v1\/aquarius/gi, '')
}
if (key.includes('brizo')) {
keyCleaned = key.replace(/\/api\/v1\/brizo/gi, '')
}
return keyCleaned
}
const toc = api => {
const items = Object.keys(api.paths).map(
key => `<li key=${key}>
<a href="#${slugify(cleanKey(key))}"><code>${cleanKey(
key
)}</code></a>
</li>`
)
return `<ul>${items}</ul>`
}
const SwaggerMeta = ({ contact, license }) => (
<ul className={styles.swaggerMeta}>
{contact && (
<li>
<a href={`mailto:${contact.email}`}>{contact.email}</a>
</li>
)}
{license && (
<li>
<a href={license.url}>{license.name}</a>
</li>
)}
</ul>
)
SwaggerMeta.propTypes = {
contact: PropTypes.object,
license: PropTypes.object
}
const ParameterExample = ({ properties }) => (
//
// HEADS UP!
//
// Constructing the example request body here based on the defined properties
// where `key` is the name of the property, and `properties[key].example` is
// the value for it.
//
// Making prism.js pick up on the strings only output didn't work out so well
// so the spans and classes this plugin would add are added manually here. Since we
// include the prism css file globally this is picked up by that.
//
// But this can only work if all keys and values are manually constructed here, which
// is almost impossible to do for deep nested objects or arrays as example value. Running
// that code through `JSON.stringify` won't syntax highlight that part of the code.
//
<pre className="language-json">
<code className="language-json">
{'{'}
{properties &&
Object.keys(properties).map(key => (
<div key={key}>
<span className="token property">{` "${key}"`}</span>
<span className="token operator">{`: `}</span>
{properties[key].type === 'string' && (
<span className="token string">{`"${
properties[key].example
}"`}</span>
)}
{(properties[key].type === 'integer' ||
properties[key].type === 'number') && (
<span className="token number">
{`${properties[key].example}`}
</span>
)}
{(properties[key].type === 'array' ||
properties[key].type === 'object') &&
JSON.stringify(properties[key].example, null, 2)}
,
</div>
))}
{'}'}
</code>
</pre>
)
ParameterExample.propTypes = {
properties: PropTypes.object
}
const Parameters = ({ parameters }) => (
<>
<h4 className={styles.subHeading}>Parameters</h4>
{parameters.map(parameter => {
const { name, type, required, description, schema } = parameter
return (
<div className={styles.parameters} key={parameter.name}>
<h5>
<code>{name}</code>
{required && (
<span
className={styles.parameterRequired}
title="required parameter"
>
*
</span>
)}
<span className={styles.parameterType}>{type}</span>
</h5>
<p>{description}</p>
{schema && (
<ParameterExample properties={schema.properties} />
)}
</div>
)
})}
</>
)
const Responses = ({ responses }) => (
<>
<h4 className={styles.subHeading}>Responses</h4>
{Object.keys(responses).map(key => (
<div key={key} className={styles.response}>
<code>{key}</code> {responses[key].description}
</div>
))}
</>
)
const Method = ({ keyName, value }) => {
const { summary, description, parameters, responses } = value
return (
<div className={styles.method}>
<h3 className={styles.pathMethod} data-type={keyName}>
{keyName}
</h3>
<p>{summary}</p>
{description && <p>{description}</p>}
{/*
{consumes &&
consumes.map((item, i) => (
<div key={i}>
<code>{item}</code>
</div>
))}
*/}
{parameters && parameters.length && (
<Parameters parameters={parameters} />
)}
{responses && Object.keys(responses).length !== 0 && (
<Responses responses={responses} />
)}
</div>
)
}
Method.propTypes = {
keyName: PropTypes.string,
value: PropTypes.object
}
const Paths = ({ paths }) =>
Object.entries(paths).map(([key, value]) => (
<div key={key}>
<h2 id={slugify(cleanKey(key))} className={styles.pathName}>
<code>{cleanKey(key)}</code>
</h2>
{Object.entries(value).map(([key, value]) => (
<Method key={key} keyName={key} value={value} />
))}
</div>
))
const BasePath = ({ host, basePath }) => (
<div className={styles.basePath}>
<h2>Base Path</h2>
<code>
<span>{host}</span>
{basePath}
</code>
</div>
)
BasePath.propTypes = {
host: PropTypes.string,
basePath: PropTypes.string
}
export default class ApiSwaggerTemplate extends Component {
static propTypes = {
data: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
pageContext: PropTypes.object.isRequired
}
render() {
const { location, data, pageContext } = this.props
const sections = data.allSectionsYaml.edges
const { api } = pageContext
const { host, basePath, info, paths } = api
const { title, description, version, license, contact } = info
// output section title as defined in sections.yml
const sectionTitle = sections.map(({ node }) => {
// compare section against section title from sections.yml
if (node.title.toLowerCase().includes('references')) {
return node.title
}
})
return (
<>
<Helmet>
<body className={'references'} />
</Helmet>
<SEO
title={title}
description={description}
slug={pageContext.slug}
article
/>
<Layout location={location}>
<HeaderSection title={sectionTitle} />
<Content>
<main className={stylesDoc.wrapper}>
<aside className={stylesDoc.sidebar}>
<Sidebar
location={location}
sidebar={'references'}
collapsed
toc
tableOfContents={toc(api)
.split(',')
.join('')}
/>
</aside>
<article className={stylesDoc.main}>
<DocHeader
title={title}
description={description}
prepend={
<span className={styles.version}>
{version}
</span>
}
/>
{(contact || license) && (
<SwaggerMeta
contact={contact}
license={license}
/>
)}
{(host || basePath) && (
<BasePath host={host} basePath={basePath} />
)}
<Paths paths={paths} />
<DocFooter
url={`https://github.com/oceanprotocol/${title.toLowerCase()}`}
externalName={`${title} Swagger spec`}
/>
</article>
</main>
</Content>
</Layout>
</>
)
}
}
export const apiSwaggerQuery = graphql`
query {
allSectionsYaml {
edges {
node {
title
description
link
}
}
}
}
`

View File

@ -0,0 +1,132 @@
@import 'variables';
.version {
font-size: $font-size-base;
font-family: $font-family-monospace;
color: $brand-grey-light;
}
.swaggerMeta {
margin-top: -($spacer);
padding: 0;
font-size: $font-size-small;
li {
display: inline-block;
margin-left: $spacer;
&:first-child {
margin-left: 0;
}
&:before { display: none;}
}
}
.basePath {
margin-top: $spacer;
h2 {
font-size: $font-size-h3;
border-bottom: 1px solid $brand-grey-lighter;
padding-bottom: $spacer / 2;
margin-top: $spacer * 2;
margin-bottom: $spacer;
}
span {
color: $brand-grey-light;
}
code {
// stylelint-disable-next-line
font-size: $font-size-large !important;
font-weight: $font-weight-bold;
}
}
.pathName {
font-size: $font-size-h3;
border-bottom: 1px solid $brand-grey-lighter;
padding-bottom: $spacer / 2;
margin-top: $spacer * 2;
margin-bottom: $spacer;
code {
// stylelint-disable-next-line
background: none !important;
}
}
.pathMethod {
font-size: $font-size-base;
font-family: $font-family-monospace;
margin-bottom: $spacer / 4;
margin-top: 0;
display: inline-block;
padding: $spacer / 8 $spacer / 3;
border-radius: $border-radius;
text-transform: uppercase;
&[data-type='get'] {
background: rgba($green, .4);
}
&[data-type='post'] {
background: rgba($brand-blue, .4);
}
&[data-type='put'] {
background: rgba($brand-violet, .3);
}
&[data-type='delete'] {
background: rgba($red, .4);
}
}
.method {
padding: $spacer / 2;
border: 1px solid $brand-grey-lighter;
margin-bottom: $spacer;
border-radius: $border-radius;
}
.subHeading {
font-size: $font-size-h5;
}
.parameters {
h5 {
font-size: $font-size-small;
margin-bottom: $spacer / 4;
}
pre {
max-height: 80vh;
code {
padding: $spacer / $line-height;
}
}
}
.parameterRequired {
font-size: $font-size-small;
vertical-align: top;
color: $brand-purple;
}
.parameterType {
font-weight: $font-weight-base;
margin-left: $spacer / 4;
color: $brand-grey-light;
}
.response {
margin-bottom: $spacer / 4;
code {
margin-right: $spacer / 4;
}
}

View File

@ -27,7 +27,7 @@ const DocMain = ({ title, description, tableOfContents, post, single }) => (
DocMain.propTypes = { DocMain.propTypes = {
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired, description: PropTypes.string.isRequired,
tableOfContents: PropTypes.string.isRequired, tableOfContents: PropTypes.string,
post: PropTypes.object.isRequired, post: PropTypes.object.isRequired,
single: PropTypes.bool single: PropTypes.bool
} }
@ -54,6 +54,8 @@ export default class DocTemplate extends Component {
} }
}) })
const isApiSection = location.pathname.includes('/references/')
return ( return (
<> <>
<Helmet> <Helmet>
@ -77,12 +79,22 @@ export default class DocTemplate extends Component {
<Sidebar <Sidebar
location={location} location={location}
sidebar={section} sidebar={section}
collapsed={isApiSection}
toc={
isApiSection &&
!location.pathname.includes(
'/references/introduction/'
)
}
tableOfContents={tableOfContents}
/> />
</aside> </aside>
<DocMain <DocMain
title={title} title={title}
description={description} description={description}
tableOfContents={tableOfContents} tableOfContents={
!isApiSection && tableOfContents
}
post={post} post={post}
/> />
</main> </main>

View File

@ -1,4 +1,5 @@
User-agent: * User-agent: *
Disallow: */test Disallow: */test
Disallow: */references/petstore
sitemap: https://docs.oceanprotocol.com/sitemap.xml sitemap: https://docs.oceanprotocol.com/sitemap.xml