268 lines
6.2 KiB
Go
268 lines
6.2 KiB
Go
//////////////////////////////////////////////////////////////////////////
|
|
// DN42 Registry API Server
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
package main
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
import (
|
|
"encoding/json"
|
|
"github.com/gorilla/mux"
|
|
log "github.com/sirupsen/logrus"
|
|
"net/http"
|
|
"strings"
|
|
// "time"
|
|
)
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// register the api
|
|
|
|
func init() {
|
|
RegisterAPIEndpoint(InitRegAPI)
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// called from main to initialise the API routing
|
|
|
|
func InitRegAPI(router *mux.Router) {
|
|
|
|
s := router.
|
|
Methods("GET").
|
|
PathPrefix("/registry").
|
|
Subrouter()
|
|
|
|
s.HandleFunc("/", regRootHandler)
|
|
//s.HandleFunc("/.schema", rTypeListHandler)
|
|
//s.HandleFunc("/.meta/", rTypeListHandler)
|
|
|
|
s.HandleFunc("/{type}", regTypeHandler)
|
|
s.HandleFunc("/{type}/{object}", regObjectHandler)
|
|
|
|
log.Info("Registry API installed")
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// handler utility funcs
|
|
|
|
func responseJSON(w http.ResponseWriter, v interface{}) {
|
|
|
|
// for response time testing
|
|
//time.Sleep(time.Second)
|
|
|
|
// marshal the JSON string
|
|
data, err := json.Marshal(v)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"error": err,
|
|
}).Error("Failed to marshal JSON")
|
|
}
|
|
|
|
// write back to http handler
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Write(data)
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// root handler, lists all types within the registry
|
|
|
|
func regRootHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
response := make(map[string]int)
|
|
for _, rType := range RegistryData.Types {
|
|
response[rType.Ref] = len(rType.Objects)
|
|
}
|
|
responseJSON(w, response)
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// type handler returns list of objects that match the type
|
|
|
|
func regTypeHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// request parameters
|
|
vars := mux.Vars(r)
|
|
query := r.URL.Query()
|
|
|
|
typeName := vars["type"] // type name to list
|
|
match := query["match"] // single query or match
|
|
|
|
// special case to return all types
|
|
all := false
|
|
if typeName == "*" {
|
|
match = []string{}
|
|
all = true
|
|
}
|
|
|
|
// results will hold the types to return
|
|
var results []*RegType
|
|
|
|
// check match type
|
|
if match == nil {
|
|
// exact match
|
|
|
|
// check the type object exists
|
|
rType := RegistryData.Types[typeName]
|
|
if rType == nil {
|
|
http.Error(w, "No types matching '"+typeName+"' found", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// return just a single result
|
|
results = []*RegType{rType}
|
|
|
|
} else {
|
|
// substring match
|
|
|
|
// comparisons are lower case
|
|
typeName = strings.ToLower(typeName)
|
|
|
|
// walk through the types and filter to the results list
|
|
results = make([]*RegType, 0)
|
|
for key, rType := range RegistryData.Types {
|
|
if all || strings.Contains(strings.ToLower(key), typeName) {
|
|
// match found, add to the list
|
|
results = append(results, rType)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// construct the response
|
|
response := make(map[string][]string)
|
|
for _, rType := range results {
|
|
|
|
objects := make([]string, 0, len(rType.Objects))
|
|
for key := range rType.Objects {
|
|
objects = append(objects, key)
|
|
}
|
|
|
|
response[rType.Ref] = objects
|
|
}
|
|
|
|
responseJSON(w, response)
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// object handler returns object data
|
|
|
|
// per object response structure
|
|
type RegObjectResponse struct {
|
|
Attributes [][2]string
|
|
Backlinks []string
|
|
}
|
|
|
|
func regObjectHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// request parameters
|
|
vars := mux.Vars(r)
|
|
query := r.URL.Query()
|
|
|
|
typeName := vars["type"] // object type
|
|
objName := vars["object"] // object name or match
|
|
match := query["match"] // single query or match
|
|
raw := query["raw"] // raw or decorated results
|
|
|
|
// special case to return all objects
|
|
all := false
|
|
if objName == "*" {
|
|
match = []string{}
|
|
all = true
|
|
}
|
|
|
|
// verify the type exists
|
|
rType := RegistryData.Types[typeName]
|
|
if rType == nil {
|
|
http.Error(w, "No types matching '"+typeName+"' found",
|
|
http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// results will hold the objects to return
|
|
var results []*RegObject
|
|
|
|
// check match type
|
|
if match == nil {
|
|
// exact match
|
|
|
|
// check the object exists
|
|
object := rType.Objects[objName]
|
|
if object == nil {
|
|
http.Error(w, "No objects matching '"+objName+"' found",
|
|
http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// then just create a results list with one object
|
|
results = []*RegObject{object}
|
|
|
|
} else {
|
|
// substring matching
|
|
|
|
// comparisons are lower case
|
|
objName = strings.ToLower(objName)
|
|
|
|
// walk through the type objects and filter to the results list
|
|
results = make([]*RegObject, 0)
|
|
for key, object := range rType.Objects {
|
|
if all || strings.Contains(strings.ToLower(key), objName) {
|
|
// match found, add to the list
|
|
results = append(results, object)
|
|
}
|
|
}
|
|
}
|
|
|
|
// collate the results in to the response data
|
|
if raw == nil {
|
|
// provide a decorated response
|
|
response := make(map[string]RegObjectResponse)
|
|
|
|
// for each object in the results
|
|
for _, object := range results {
|
|
|
|
// copy the raw attributes
|
|
attributes := make([][2]string, len(object.Data))
|
|
for ix, attribute := range object.Data {
|
|
attributes[ix] = [2]string{attribute.Key, attribute.Value}
|
|
}
|
|
|
|
// construct the backlinks
|
|
backlinks := make([]string, len(object.Backlinks))
|
|
for ix, object := range object.Backlinks {
|
|
backlinks[ix] = object.Ref
|
|
}
|
|
|
|
// add to the response
|
|
response[object.Ref] = RegObjectResponse{
|
|
Attributes: attributes,
|
|
Backlinks: backlinks,
|
|
}
|
|
}
|
|
|
|
responseJSON(w, response)
|
|
|
|
} else {
|
|
// provide a response with just the raw registry data
|
|
response := make(map[string][][2]string)
|
|
|
|
// for each object in the results
|
|
for _, object := range results {
|
|
|
|
attributes := make([][2]string, len(object.Data))
|
|
response[object.Ref] = attributes
|
|
|
|
// copy the raw attributes
|
|
for ix, attribute := range object.Data {
|
|
attributes[ix] = [2]string{attribute.Key, attribute.RawValue}
|
|
}
|
|
}
|
|
|
|
responseJSON(w, response)
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// end of code
|