Skip to content

Commit

Permalink
adding API calls with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mfenner committed Apr 6, 2024
1 parent da220c8 commit 12b5fd6
Show file tree
Hide file tree
Showing 14 changed files with 510 additions and 3 deletions.
60 changes: 60 additions & 0 deletions crossref/crossref.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package crossref

import (
"commonmeta/doiutils"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)

// the envelope for the JSON response from the Crossref API
type Result struct {
Status string `json:"status"`
MessageType string `json:"message-type"`
MessageVersion string `json:"message-version"`
Message Record `json:"message"`
}

// the JSON response containing the metadata for the DOI
type Record struct {
URL string `json:"URL"`
DOI string `json:"DOI"`
Type string `json:"type"`
Title []string `json:"title"`
Publisher string `json:"publisher"`
Volume string `json:"volume"`
Issue string `json:"issue"`
Page string `json:"page"`
}

var result Result

func GetCrossref(pid string) (Record, error) {
doi, err := doiutils.DOIFromUrl(pid)
if err != nil {
return Record{}, err
}
url := "https://api.crossref.org/works/" + doi
client := http.Client{
Timeout: time.Second * 10,
}
resp, err := client.Get(url)
if err != nil {
return Record{}, err
}
if resp.StatusCode >= 400 {
return Record{}, fmt.Errorf("status code error: %d %s", resp.StatusCode, resp.Status)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return Record{}, err
}
err = json.Unmarshal(body, &result)
if err != nil {
fmt.Println("error:", err)
}
return result.Message, err
}
39 changes: 39 additions & 0 deletions crossref/crossref_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package crossref_test

import (
"commonmeta/crossref"
"testing"
)

func TestGetCrossref(t *testing.T) {
t.Parallel()

type testCase struct {
doi string
want string
err error
}

journalArticle := crossref.Record{
URL: "https://api.crossref.org/works/10.7554/elife.01567",
DOI: "10.7554/elife.01567",
Publisher: "eLife Sciences Publications, Ltd",
}
postedContent := crossref.Record{
URL: "https://api.crossref.org/works/10.1101/097196",
DOI: "10.1101/097196",
Publisher: "Cold Spring Harbor Laboratory",
}

testCases := []testCase{
{doi: journalArticle.DOI, want: journalArticle.Publisher, err: nil},
{doi: postedContent.DOI, want: postedContent.Publisher, err: nil},
}
for _, tc := range testCases {
got, err := crossref.GetCrossref(tc.doi)
if tc.want != got.Publisher {
t.Errorf("Get Crossref(%v): want %v, got %v, error %v",
tc.doi, tc.want, got, err)
}
}
}
81 changes: 81 additions & 0 deletions datacite/datacite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package datacite

import (
"commonmeta/doiutils"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)

// the envelope for the JSON response from the DataCite API
type Result struct {
Data Record `json:"data"`
}

// the JSON response containing the DataCite metadata
type Record struct {
ID string `json:"id"`
Type string `json:"type"`
Attributes Attributes `json:"attributes"`
}

type Attributes struct {
DOI string `json:"doi"`
Prefix string `json:"prefix"`
Suffix string `json:"suffix"`
Creators []Creator `json:"creators"`
Publisher string `json:"publisher"`
Container Container `json:"container"`
PublicationYear int `json:"publicationYear"`
Titles []Title `json:"titles"`
Url string `json:"url"`
}

type Container struct {
ID string `json:"id"`
Name string `json:"name"`
}

type Creator struct {
Type string `json:"type"`
Identifier string `json:"identifier"`
IdentifierType string `json:"identifierType"`
Name string `json:"name"`
}

type Title struct {
Title string `json:"title"`
Language string `json:"language"`
}

var result Result

func GetDatacite(pid string) (Record, error) {
doi, err := doiutils.DOIFromUrl(pid)
if err != nil {
return Record{}, err
}
url := "https://api.datacite.org/dois/" + doi
client := http.Client{
Timeout: time.Second * 10,
}
resp, err := client.Get(url)
if err != nil {
return Record{}, err
}
if resp.StatusCode != 200 {
return Record{}, fmt.Errorf("status code error: %d %s", resp.StatusCode, resp.Status)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return Record{}, err
}
err = json.Unmarshal(body, &result)
if err != nil {
fmt.Println("error:", err)
}
return result.Data, err
}
41 changes: 41 additions & 0 deletions datacite/datacite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package datacite_test

import (
"commonmeta/datacite"
"testing"
)

func TestGetDataCite(t *testing.T) {
t.Parallel()

type testCase struct {
id string
want string
err error
}

publication := datacite.Record{
Attributes: datacite.Attributes{
DOI: "https://doi.org/10.5281/zenodo.5244404",
Url: "https://zenodo.org/record/5244404",
},
}
presentation := datacite.Record{
Attributes: datacite.Attributes{
DOI: "10.5281/zenodo.8173303",
Url: "https://zenodo.org/record/8173303",
},
}

testCases := []testCase{
{id: presentation.Attributes.DOI, want: presentation.Attributes.Url, err: nil},
{id: publication.Attributes.DOI, want: publication.Attributes.Url, err: nil},
}
for _, tc := range testCases {
got, err := datacite.GetDatacite(tc.id)
if tc.want != got.Attributes.Url {
t.Errorf("InvenioRDM ID(%v): want %v, got %v, error %v",
tc.id, tc.want, got, err)
}
}
}
2 changes: 1 addition & 1 deletion dateutils/dateutils_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dateutils_test

import (
"dateutils"
"commonmeta/dateutils"
"testing"
)

Expand Down
54 changes: 54 additions & 0 deletions doiutils/doiutils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package doiutils

import (
"net/url"
"strings"
)

// extract DOI from URL
func DOIFromUrl(str string) (string, error) {
u, err := url.Parse(str)
if err != nil {
return "", err
}
if u.Host == "" {
return str, nil
}
if u.Host != "doi.org" || !strings.HasPrefix(u.Path, "/10.") {
return "", nil
}
return strings.TrimLeft(u.Path, "/"), nil
}

// def doi_from_url(url: Optional[str]) -> Optional[str]:
// """Return a DOI from a URL"""
// if url is None:
// return None

// f = furl(url)
// # check for allowed scheme if string is a URL
// if f.host is not None and f.scheme not in ["http", "https", "ftp"]:
// return None

// # url is for a short DOI
// if f.host == "doi.org" and not f.path.segments[0].startswith("10."):
// return short_doi_as_doi(url)

// # special rules for specific hosts
// if f.host == "onlinelibrary.wiley.com":
// if f.path.segments[-1] in ["epdf"]:
// f.path.segments.pop()
// elif f.host == "www.plosone.org":
// if (
// f.path.segments[-1] in ["fetchobject.action"]
// and f.args.get("uri", None) is not None
// ):
// f.path = f.args.get("uri")
// path = str(f.path)
// match = re.search(
// r"(10\.\d{4,5}/.+)\Z",
// path,
// )
// if match is None:
// return None
// return match.group(0).lower()
25 changes: 25 additions & 0 deletions doiutils/doiutils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package doiutils_test

import (
"commonmeta/doiutils"
"testing"
)

func TestDOIFromUrl(t *testing.T) {
t.Parallel()
type testCase struct {
input string
want string
}
testCases := []testCase{
{input: "https://doi.org/10.7554/elife.01567", want: "10.7554/elife.01567"},
{input: "10.1101/097196", want: "10.1101/097196"},
}
for _, tc := range testCases {
got, err := doiutils.DOIFromUrl(tc.input)
if tc.want != got {
t.Errorf("DOI from Url(%v): want %v, got %v, error %v",
tc.input, tc.want, got, err)
}
}
}
42 changes: 42 additions & 0 deletions inveniordm/inveniordm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package inveniordm

import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)

// the JSON response containing the InvenioRDM metadata
type Record struct {
ID string `json:"id"`
DOI string `json:"doi"`
Title string `json:"title"`
}

var result Record

func GetInvenioRDM(pid string) (Record, error) {
client := http.Client{
Timeout: time.Second * 10,
}
url := "https://zenodo.org/api/records/" + pid
resp, err := client.Get(url)
if err != nil {
return Record{}, err
}
if resp.StatusCode != 200 {
return Record{}, fmt.Errorf("status code error: %d %s", resp.StatusCode, resp.Status)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return Record{}, err
}
err = json.Unmarshal(body, &result)
if err != nil {
fmt.Println("error:", err)
}
return result, err
}
39 changes: 39 additions & 0 deletions inveniordm/inveniordm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package inveniordm_test

import (
"commonmeta/inveniordm"
"testing"
)

func TestGetInvenioRDM(t *testing.T) {
t.Parallel()

type testCase struct {
id string
want string
err error
}

publication := inveniordm.Record{
ID: "5244404",
DOI: "10.5281/zenodo.5244404",
Title: "The Origins of SARS-CoV-2: A Critical Review",
}
presentation := inveniordm.Record{
ID: "8173303",
DOI: "10.5281/zenodo.8173303",
Title: "11 July 2023 (Day 2) CERN – NASA Open Science Summit Sketch Notes",
}

testCases := []testCase{
{id: presentation.ID, want: presentation.Title, err: nil},
{id: publication.ID, want: publication.Title, err: nil},
}
for _, tc := range testCases {
got, err := inveniordm.GetInvenioRDM(tc.id)
if tc.want != got.Title {
t.Errorf("InvenioRDM ID(%v): want %v, got %v, error %v",
tc.id, tc.want, got, err)
}
}
}
Loading

0 comments on commit 12b5fd6

Please sign in to comment.