Skip to content

Commit 716cc93

Browse files
committed
golang port
1 parent a8958b6 commit 716cc93

File tree

6 files changed

+152
-97
lines changed

6 files changed

+152
-97
lines changed

Dockerfile

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
FROM golang:alpine AS builder
3+
WORKDIR /go/src/app
4+
COPY . .
5+
RUN apk add --no-cache git
6+
RUN go get -d -v ./...
7+
RUN go install -v ./...
8+
9+
FROM alpine:latest
10+
RUN apk --no-cache add ca-certificates
11+
COPY --from=builder /go/bin/app /app
12+
ENTRYPOINT ./app
13+
LABEL Name=isbn-authors Version=1.0.0
14+
EXPOSE 8093

Procfile

-1
This file was deleted.

README.md

+1-17
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,7 @@ simple http wrapper around [OCLC Classify](http://classify.oclc.org/classify2/ap
33

44
run:
55

6-
~ git clone https://github.com/atomotic/isbn-authors
7-
~ cd isbn-authors
8-
~ pip install -r requirements.txt
6+
docker run -d -p 8093:8093 atomotic/isbn-authors
97

10-
# install redis, used to cache results.
11-
# apt-get install redis-server (linux)
12-
# brew install redis (macos)
13-
~ redis-server
14-
15-
~ FLASK_APP=app.py FLASK_DEBUG=1 flask run
16-
17-
~ http :5000/api/v1/authors/{ISBN}
18-
19-
---
208

21-
examples at:
22-
[https://isbn-authors.herokuapp.com](https://isbn-authors.herokuapp.com/)
239

24-
* https://isbn-authors.herokuapp.com/api/v1/authors/9788806189877
25-
* https://isbn-authors.herokuapp.com/api/v1/authors/9788845930874

app.py

-72
This file was deleted.

main.go

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"encoding/xml"
6+
"errors"
7+
"fmt"
8+
"io/ioutil"
9+
"log"
10+
"net/http"
11+
"strings"
12+
13+
"github.com/gorilla/mux"
14+
"github.com/knakk/sparql"
15+
bolt "go.etcd.io/bbolt"
16+
)
17+
18+
var db *bolt.DB
19+
20+
const oclcAPI = "http://classify.oclc.org/classify2/Classify?isbn="
21+
22+
type Book struct {
23+
Work Work `xml:"work" json:"book"`
24+
Response Response `xml:"response" json:"-"`
25+
Authors []Author `xml:"authors>author" json:"authors"`
26+
}
27+
type Work struct {
28+
Title string `xml:"title,attr" json:"title"`
29+
}
30+
type Response struct {
31+
Code int `xml:"code,attr" json:"-"`
32+
}
33+
type Author struct {
34+
Viaf string `xml:"viaf,attr" json:"viaf"`
35+
Wikidata string `json:"wikidata"`
36+
Text string `xml:",chardata" json:"name"`
37+
}
38+
39+
func getBookAuthors(isbn string) (Book, error) {
40+
var book Book
41+
42+
resp, err := http.Get(fmt.Sprintf("%s%s", oclcAPI, isbn))
43+
if err != nil {
44+
return book, err
45+
}
46+
defer resp.Body.Close()
47+
body, err := ioutil.ReadAll(resp.Body)
48+
49+
err = xml.Unmarshal([]byte(body), &book)
50+
if err != nil {
51+
return book, err
52+
}
53+
54+
if book.Response.Code == 0 || book.Response.Code == 2 || book.Response.Code == 4 {
55+
for i, author := range book.Authors {
56+
wd, err := sparql.NewRepo("https://query.wikidata.org/sparql")
57+
if err != nil {
58+
return book, err
59+
}
60+
query := fmt.Sprintf("SELECT ?q WHERE { ?q wdt:P214 '%s'.}", author.Viaf)
61+
res, err := wd.Query(query)
62+
if err != nil {
63+
return book, err
64+
}
65+
if len(res.Results.Bindings) > 0 {
66+
Q := strings.Split(res.Results.Bindings[0]["q"].Value, "/")[4]
67+
book.Authors[i].Wikidata = Q
68+
}
69+
}
70+
return book, nil
71+
} else {
72+
return book, errors.New("0 results.")
73+
}
74+
75+
}
76+
77+
func IsbnAPI(w http.ResponseWriter, r *http.Request) {
78+
vars := mux.Vars(r)
79+
isbn := vars["isbn"]
80+
81+
err := db.Update(func(tx *bolt.Tx) error {
82+
83+
b := tx.Bucket([]byte("books"))
84+
85+
cached := b.Get([]byte(isbn))
86+
87+
if cached != nil {
88+
w.Header().Set("Content-Type", "application/json")
89+
w.WriteHeader(http.StatusOK)
90+
fmt.Fprintf(w, "%s", cached)
91+
} else {
92+
book, err := getBookAuthors(isbn)
93+
if err != nil {
94+
w.WriteHeader(http.StatusNotFound)
95+
fmt.Fprintf(w, "<book not found>")
96+
return nil
97+
}
98+
99+
bookJSON, _ := json.Marshal(book)
100+
err = b.Put([]byte(isbn), []byte(bookJSON))
101+
if err != nil {
102+
return err
103+
}
104+
w.Header().Set("Content-Type", "application/json")
105+
w.WriteHeader(http.StatusOK)
106+
fmt.Fprintf(w, "%s", bookJSON)
107+
}
108+
return nil
109+
})
110+
if err != nil {
111+
http.Error(w, err.Error(), http.StatusInternalServerError)
112+
}
113+
}
114+
115+
func main() {
116+
var err error
117+
db, err = bolt.Open("isbn-authors.cache", 0600, nil)
118+
if err != nil {
119+
log.Fatal(err)
120+
}
121+
defer db.Close()
122+
123+
db.Update(func(tx *bolt.Tx) error {
124+
_, err := tx.CreateBucket([]byte("books"))
125+
if err != nil {
126+
return fmt.Errorf("create bucket: %s", err)
127+
}
128+
return nil
129+
})
130+
131+
r := mux.NewRouter()
132+
r.HandleFunc("/isbn/{isbn}", IsbnAPI)
133+
fmt.Println("server running on http://localhost:8093/isbn/{$ISBN}")
134+
135+
http.ListenAndServe(":8093", r)
136+
137+
}

requirements.txt

-7
This file was deleted.

0 commit comments

Comments
 (0)