### Install dictybase/literature Source: https://github.com/dictybase/literature/blob/develop/README.md Use the go get command to install the library. Requires Go 1.26 or later. ```bash go get github.com/dictybase/literature ``` -------------------------------- ### Initialize Client with options Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/client.md Example of creating a new PubMed client with custom timeout, user agent, API key, tool name, and email. ```go client, err := literature.New( literature.WithTimeout(60*time.Second), literature.WithUserAgent("MyApp/1.0"), literature.WithAPIKey(os.Getenv("NCBI_API_KEY")), literature.WithTool("my-tool"), literature.WithEmail(os.Getenv("NCBI_EMAIL")), ) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Create EuropePMC client with options Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/europepmc-client.md Example of creating a client with email and timeout options. Throws error only if an option fails. ```go client, err := literature.NewEuropePMCClient( literature.WithEuropePMCEmail("research@university.edu"), literature.WithEuropePMCTimeout(60*time.Second), ) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Example invocations of lit-cli Source: https://github.com/dictybase/literature/blob/develop/examples/cli-tool/README.md Concrete examples of running lit-cli with a PMID, a DOI, and a custom output filename. ```bash # examples go run . 12345678 go run . 10.1016/j.jmb.2010.08.037 go run . -o jmb-2010.pdf 10.1016/j.jmb.2010.08.037 ``` -------------------------------- ### Create OpenAlex client with email option Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Example of creating a client with the WithOpenAlexEmail option. Returns an error only if an option fails. ```go client, err := literature.NewOpenAlexClient( literature.WithOpenAlexEmail("you@example.org"), ) if err != nil { log.Fatal(err) } ``` -------------------------------- ### GetCitationMetrics example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Returns citation count, FWCI, and normalized percentiles for a work. Throws *Error from GetWork. ```go metrics, err := client.GetCitationMetrics("W2100837269") if err != nil { log.Fatal(err) } fmt.Printf("Cited by %d, FWCI %.2f, percentiles %.2f-%.2f\n", metrics.CitedByCount, metrics.FWCI, metrics.PercentileMin, metrics.PercentileMax) ``` -------------------------------- ### Optimize Article Fetching and Context Usage Source: https://github.com/dictybase/literature/blob/develop/README.md Examples of using GetArticles for convenience, iterating for individual article fetching, and implementing context timeouts for long-running operations. ```go // Convenience grouping; still sends one sequential request per PMID. articles, err := client.GetArticles([]string{"12345678", "87654321", "11111111"}) // Calling GetArticle separately sends the same number of requests. for _, pmid := range pmids { article, err := client.GetArticle(pmid) // ... } // Use context with timeout for long-running operations ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // EuropePMC rate-limit and retry options currently have no effect; // callers must manage request pacing and retries. ``` -------------------------------- ### CLI Commands for OpenAlex Data Extraction Source: https://github.com/dictybase/literature/blob/develop/examples/openalex-cli/README.md Examples of how to run the CLI tool to fetch metadata, metrics, references, and citing works using various identifiers. ```bash go run . work W2100837269 # metadata (OpenAlex ID, PMID, or DOI) go run . metrics 10.1038/nature12373 # citation count, FWCI, percentiles go run . refs PMID:23842501 # all works cited by the article go run . citing W2100837269 --limit 10 # one page of citing works ``` -------------------------------- ### GetPDFURLs usage example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/europepmc-client.md Calls GetPDFURLs with a PMID, logs fatal error on failure, and prints each URL's site, URL, and availability code. ```go urls, err := client.GetPDFURLs("25844567") if err != nil { log.Fatal(err) } for _, u := range urls { fmt.Println(u.Site, u.URL, u.AvailabilityCode) } ``` -------------------------------- ### Handle PDFError types Source: https://github.com/dictybase/literature/blob/develop/README.md Example of using errors.As to inspect and handle specific PDFError types. ```go err := pdfService.DownloadArticlePDF("12345", "test.pdf") if err != nil { var pdfErr *PDFError if errors.As(err, &pdfErr) { switch pdfErr.Type { case PDFErrorArticleNotFound: fmt.Println("Article not found") case PDFErrorPMCIDNotFound: fmt.Println("Article not available in PMC") case PDFErrorPDFNotAvailable: fmt.Println("PDF not available") case PDFErrorDownloadFailed: fmt.Printf("Download failed: %v\n", pdfErr.Err) } } } ``` -------------------------------- ### Search EuropePMC example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/europepmc-client.md Searches EuropePMC with a query expression, using cursor-based pagination. Throws *Error InvalidInput for empty query or APIError on search failure with Query set. ```go res, err := client.Search("cancer AND immunotherapy", literature.WithEuropePMCLimit(50), literature.WithEuropePMCResultType("core"), ) if err != nil { log.Fatal(err) } fmt.Printf("Total: %d\n", res.Total) for _, a := range res.Articles { fmt.Println(a.Title, a.Journal.Title) } ``` -------------------------------- ### Catching *Error in consumer code Source: https://github.com/dictybase/literature/blob/develop/_autodocs/errors.md Example of how to catch and handle *Error in consumer code. ```APIDOC ## Catching *Error in consumer code ### Description Example of how to catch and handle *Error in consumer code. ### Example ```go article, err := client.GetArticle("invalid-pmid") if err != nil { var litErr *literature.Error if errors.As(err, &litErr) { switch litErr.Type { case literature.ErrorTypeInvalidInput: // handle case literature.ErrorTypeArticleNotFound: // handle case literature.ErrorTypeRateLimit: // handle default: // API / network / parse / timeout } if litErr.PMID != "" { fmt.Println("related PMID:", litErr.PMID) } } } ``` `litErr.IsType(literature.ErrorTypeInvalidInput)` also works for single-type checks. ``` -------------------------------- ### GetWork example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Fetches a single work by OpenAlex ID, PMID, or DOI. The ID is passed to openAlexService.FetchWork after stripping the OpenAlex URL prefix. Errors are mapped via createWorkError. ```go work, err := client.GetWork("W2100837269") if err != nil { log.Fatal(err) } fmt.Println(work.Title, work.CitedByCount) ``` -------------------------------- ### GetWorks batch lookup example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Batch-lookup works by OpenAlex IDs. Identifiers are sent in chunks of 50 (filterChunkSize). Uses fetchWorksByFilter("ids.openalex", ids, stripOpenAlexIDPrefix). ```go works, err := client.GetWorks([]string{"W2100837269", "W2103656553"}) if err != nil { log.Fatal(err) } ``` -------------------------------- ### GetCitingWorks example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Fetches one page of works that cite the given work, using filter=cites:. Supports pagination via cursor. Throws *Error with specific error types. ```go page, err := client.GetCitingWorks("W2100837269", literature.WithOpenAlexPerPage(25), literature.WithOpenAlexSort("cited_by_count:desc"), ) if err != nil { log.Fatal(err) } fmt.Println("Total:", page.TotalCount, "Next cursor:", page.Cursor) for _, w := range page.Results { fmt.Println(w.Title, w.CitedByCount) } ``` -------------------------------- ### GetReferencedWorks example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Fetches all works cited by a given work ID. Returns an empty non-nil slice if the work has no references. Throws *Error from GetWork/GetWorks. ```go referenced, err := client.GetReferencedWorks("W2100837269") if err != nil { log.Fatal(err) } for _, ref := range referenced { fmt.Println(ref.Title, ref.PublicationYear) } ``` -------------------------------- ### GetArticle by PMID example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/europepmc-client.md Fetches an article by PMID using query ext_id: with resultType=core, pageSize=1. Throws *Error with types InvalidInput, APIError, ArticleNotFound, ParseError; errors carry PMID. ```go article, err := client.GetArticle("25844567") if err != nil { log.Fatal(err) } fmt.Println(article.Title, article.CitedByCount, article.IsOpenAccess) ``` -------------------------------- ### GetArticleByDOI example Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/europepmc-client.md Fetches an article directly by DOI using query DOI:"" with resultType=core, pageSize=1. Throws same errors as GetArticle but errors carry DOI instead of PMID. ```go article, err := client.GetArticleByDOI("10.1038/nature12373") if err != nil { log.Fatal(err) } fmt.Println(article.PMID) ``` -------------------------------- ### GetPDFURLs Source: https://github.com/dictybase/literature/blob/develop/README.md Gets all available PDF URLs for the given PMID. ```APIDOC ## GetPDFURLs ### Description Gets all available PDF URLs for the given PMID. ### Method Function ### Signature `GetPDFURLs(pmid string) ([]EuropePMCFullTextURL, error)` ### Parameters #### Path Parameters - **pmid** (string) - Required - The PubMed ID of the article ### Response #### Success Response - **urls** ([]EuropePMCFullTextURL) - List of PDF URLs - **err** (error) - Error if retrieval fails ``` -------------------------------- ### Configure Client with API Credentials Source: https://github.com/dictybase/literature/blob/develop/README.md Initialize the client using environment variables for NCBI API key, tool name, and contact email. ```go import ( "os" "github.com/dictybase/literature" ) client, err := literature.New( literature.WithAPIKey(os.Getenv("NCBI_API_KEY")), literature.WithTool("my-tool"), literature.WithEmail(os.Getenv("NCBI_EMAIL")), ) ``` -------------------------------- ### Build and Format Commands Source: https://github.com/dictybase/literature/blob/develop/README.md Standard commands for formatting, linting, building, and benchmarking the codebase. ```bash # Format code gofumpt -w . # Lint codebase golangci-lint run # Build go build # Run benchmarks go test -bench=. -benchmem # Check for race conditions go test -race ./... ``` -------------------------------- ### Catching *PDFError Source: https://github.com/dictybase/literature/blob/develop/_autodocs/errors.md Example of how to catch a *PDFError using errors.As and switch on the error type. ```APIDOC ## Catching *PDFError ### Description Example code demonstrating how to handle *PDFError using errors.As and a type switch. ### Example ```go err := client.DownloadPDF("12345", "out.pdf") if err != nil { var pdfErr *literature.PDFError if errors.As(err, &pdfErr) { switch pdfErr.Type { case literature.PDFErrorArticleNotFound: // ... case literature.PDFErrorPMCIDNotFound: // ... case literature.PDFErrorPDFNotAvailable: // ... case literature.PDFErrorDownloadFailed: fmt.Printf("download failed: %v\n", pdfErr.Err) } } } ``` ``` -------------------------------- ### Retrieve Basic Article Information Source: https://github.com/dictybase/literature/blob/develop/README.md Demonstrates how to initialize the client and fetch detailed information for a specific article using its PMID. ```go client, err := literature.NewEuropePMCClient() if err != nil { log.Fatal(err) } // Get detailed article information article, err := client.GetArticle("25844567") if err != nil { log.Fatal(err) } fmt.Printf("Title: %s\n", article.Title) fmt.Printf("Journal: %s (%s)\n", article.Journal.Title, article.Journal.ISOAbbreviation) fmt.Printf("Publication Year: %s\n", article.PubYear) fmt.Printf("Open Access: %t\n", article.IsOpenAccess) fmt.Printf("Citations: %d\n", article.CitedByCount) // Print authors with affiliations for _, author := range article.Authors { fmt.Printf("Author: %s", author.FullName) if author.ORCID != "" { fmt.Printf(" (ORCID: %s)", author.ORCID) } fmt.Println() for _, affiliation := range author.Affiliations { fmt.Printf(" - %s\n", affiliation.Affiliation) } } // Print MeSH headings if len(article.MeshHeadings) > 0 { fmt.Println("\nMeSH Headings:") for _, mesh := range article.MeshHeadings { majorTopic := "" if mesh.MajorTopic { majorTopic = " (Major Topic)" } fmt.Printf(" - %s%s\n", mesh.DescriptorName, majorTopic) } } ``` -------------------------------- ### Run lit-cli with go run Source: https://github.com/dictybase/literature/blob/develop/examples/cli-tool/README.md Build and run the package from the examples/cli-tool/ directory. The first command runs with default output filename (.pdf), the second uses the -o flag to specify a custom output filename. ```bash # from examples/cli-tool/ go run . # custom output filename (default: .pdf) go run . -o paper.pdf ``` -------------------------------- ### Perform Advanced Search with Options Source: https://github.com/dictybase/literature/blob/develop/README.md Shows how to configure the client with an email address and perform a search with specific limits and result types. ```go client, err := literature.NewEuropePMCClient( literature.WithEuropePMCEmail("research@university.edu"), ) if err != nil { log.Fatal(err) } // Search for articles with advanced options searchResult, err := client.Search( "cancer AND immunotherapy", literature.WithEuropePMCLimit(50), literature.WithEuropePMCResultType("core"), ) if err != nil { log.Fatal(err) } fmt.Printf("Found %d articles for query: %s\n", searchResult.Total, searchResult.Query) for i, article := range searchResult.Articles { fmt.Printf("%d. %s\n", i+1, article.Title) fmt.Printf(" Journal: %s (%s)\n", article.Journal.Title, article.PubYear) fmt.Printf(" Open Access: %t, Has PDF: %t\n", article.IsOpenAccess, article.HasPDF) if article.Abstract != "" { abstract := article.Abstract if len(abstract) > 200 { abstract = abstract[:200] + "..." } fmt.Printf(" Abstract: %s\n", abstract) } fmt.Println() } ``` -------------------------------- ### Configure EuropePMC Client Source: https://github.com/dictybase/literature/blob/develop/README.md Initialize the EuropePMC client with custom timeout, user agent, and contact email settings. ```go client, err := literature.NewEuropePMCClient( literature.WithEuropePMCTimeout(60*time.Second), literature.WithEuropePMCUserAgent("MyApp/1.0"), literature.WithEuropePMCEmail("contact@myapp.com"), ) ``` -------------------------------- ### GET /works Source: https://github.com/dictybase/literature/blob/develop/_autodocs/endpoints.md Searches for works on OpenAlex using filters, pagination, and sorting. Supports optional authentication parameters for polite pool or premium access. ```APIDOC ## GET /works ### Description Searches for works on OpenAlex using filters, pagination, and sorting. Supports optional authentication parameters for polite pool or premium access. ### Method GET ### Endpoint /works ### Parameters #### Query Parameters - **filter** (string) - Optional - Filter criteria, e.g., `cites:` or `ids.openalex:A|B|C` or `pmid:...` (OR-separated chunks of ≤50). - **per-page** (integer) - Optional - Number of results per page, if > 0. - **cursor** (string) - Optional - Cursor for pagination. - **sort** (string) - Optional - Sort order, e.g., `cited_by_count:desc`. - **mailto** (string) - Optional - Email address for polite pool access. - **api_key** (string) - Optional - API key for premium access. ### Response #### Success Response (200) - **meta** (object) - Contains `count`, `per_page`, `cursor`. - **results** (array) - List of works. #### Error Responses - **404** - ErrOpenAlexNotFound - "work not found" - **429** - ErrOpenAlexRateLimited - "rate limit exceeded" - **other** - API request failed with status ``` -------------------------------- ### Create EuropePMC client with custom options Source: https://github.com/dictybase/literature/blob/develop/_autodocs/configuration.md Shows how to instantiate a EuropePMC client using NewEuropePMCClient with a custom timeout, user agent, contact email, and default result type. The retry and rate limit options are placeholders and have no effect. ```go client, err := literature.NewEuropePMCClient( literature.WithEuropePMCTimeout(60*time.Second), literature.WithEuropePMCUserAgent("MyApp/1.0"), literature.WithEuropePMCEmail("contact@myapp.com"), literature.WithEuropePMCDefaultResultType("core"), ) ``` -------------------------------- ### Client constructor signature Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/client.md The signature for the New constructor, which creates a client and applies functional options. ```go func New(opts ...Option) (*Client, error) ``` -------------------------------- ### NewEuropePMCClient constructor signature Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/europepmc-client.md Constructor signature for creating a EuropePMC client. Applies options in order; failure aborts with 'failed to apply option: '. Defaults include 30s timeout, base URL, user agent, maxRetries 3, retryDelay 1s, requestsPerSecond 10, resultType 'core', format 'json'. ```go func NewEuropePMCClient(opts ...EuropePMCOption) (*EuropePMCClient, error) ``` -------------------------------- ### Clone the repository Source: https://github.com/dictybase/literature/blob/develop/README.md Initial steps to fork and clone the literature repository to your local machine. ```bash git clone https://github.com/yourusername/literature.git cd literature ``` -------------------------------- ### NewEuropePMCClient Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/europepmc-client.md Creates a new EuropePMC client with default settings and applies provided options in order. Returns an error if any option fails. ```APIDOC ## NewEuropePMCClient ### Description Creates a new EuropePMC client and applies options in order. Failure to apply an option aborts with `failed to apply option: `. ### Method Constructor ### Signature ```go func NewEuropePMCClient(opts ...EuropePMCOption) (*EuropePMCClient, error) ``` ### Parameters - **opts** (`...EuropePMCOption`) - Optional - Options to configure the client. ### Defaults | Setting | Default | |---------|---------| | `httpClient.Timeout` | `30 * time.Second` | | `baseURL` | `https://www.ebi.ac.uk/europepmc/webservices/rest` | | `userAgent` | `europepmc-go-client/1.0` | | `maxRetries` | `3` | | `retryDelay` | `time.Second` | | `requestsPerSecond` | `10.0` | | `defaultResultType` | `"core"` | | `defaultFormat` | `"json"` | | `email` | `""` | ### Example ```go client, err := literature.NewEuropePMCClient( literature.WithEuropePMCEmail("research@university.edu"), literature.WithEuropePMCTimeout(60*time.Second), ) if err != nil { log.Fatal(err) } ``` ### Throws - Error only if an `EuropePMCOption` fails. ``` -------------------------------- ### Run code standards tools Source: https://github.com/dictybase/literature/blob/develop/README.md Commands to format code, run the linter, and execute tests. ```bash # Format code gofumpt -w . # Run linter golangci-lint run # Run tests gotestsum --format-hide-empty-pkg --format testdox --format-icons hivis ``` -------------------------------- ### Build commands for lit-cli module Source: https://github.com/dictybase/literature/blob/develop/examples/cli-tool/README.md Build commands that work for the Go module. The package spans multiple files, so building a single file (go build ./main.go) does not work. ```bash go build . # or go build ./... # or go run . ``` -------------------------------- ### GET /works/ Source: https://github.com/dictybase/literature/blob/develop/_autodocs/endpoints.md Fetches a single work from OpenAlex by its ID, which can be an OpenAlex ID, a full URL, a PMID, or a DOI URL. Supports optional authentication parameters for polite pool or premium access. ```APIDOC ## GET /works/ ### Description Fetches a single work from OpenAlex by its ID. The ID can be an OpenAlex ID (W...), a full OpenAlex URL, a PMID (PMID:...), or a DOI URL (https://doi.org/). ### Method GET ### Endpoint /works/ ### Parameters #### Path Parameters - **id** (string) - Required - The OpenAlex ID, full URL, PMID, or DOI URL of the work. #### Query Parameters - **mailto** (string) - Optional - Email address for polite pool access. - **api_key** (string) - Optional - API key for premium access. ### Headers - **User-Agent** - Required - User agent string. - **Accept** - Required - application/json ### Response #### Success Response (200) - **OpenAlexAPIWork** (object) - The work data. #### Error Responses - **404** - ErrOpenAlexNotFound - "work not found" - **429** - ErrOpenAlexRateLimited - "rate limit exceeded" - **other** - API request failed with status ``` -------------------------------- ### Fetch PubMed Article Source: https://github.com/dictybase/literature/blob/develop/README.md Initialize a PubMed client and retrieve article details using a PMID. ```go package main import ( "fmt" "log" "github.com/dictybase/literature" ) func main() { // Create a PubMed client for biomedical literature client, err := literature.New() if err != nil { log.Fatal(err) } // Fetch an article by PMID article, err := client.GetArticle("12345678") if err != nil { log.Fatal(err) } fmt.Printf("Title: %s\n", article.Title) fmt.Printf("Authors: %v\n", article.Authors) } ``` -------------------------------- ### Testing Commands Source: https://github.com/dictybase/literature/blob/develop/README.md Commands for running tests, generating coverage reports, and executing integration tests. ```bash # Run all tests gotestsum --format-hide-empty-pkg --format testdox --format-icons hivis # Run specific test gotestsum --format-hide-empty-pkg --format testdox --format-icons hivis -- -run TestFindSimilar ./... # Run with verbose output gotestsum --format-hide-empty-pkg --format standard-verbose --format-icons hivis # Coverage report go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out # Integration tests (requires network) go test -tags=integration ./... ``` -------------------------------- ### Perform concurrent article fetches Source: https://github.com/dictybase/literature/blob/develop/README.md Demonstrates safe concurrent article fetching using multiple goroutines. ```go // Safe to use from multiple goroutines var wg sync.WaitGroup pmids := []string{"12345678", "87654321", "11111111"} for _, pmid := range pmids { wg.Add(1) go func(pmid string) { defer wg.Done() article, err := client.GetArticle(pmid) if err != nil { log.Printf("Error fetching %s: %v", pmid, err) return } fmt.Printf("Fetched: %s\n", article.Title) }(pmid) } wg.Wait() ``` -------------------------------- ### NewOpenAlexClient constructor signature Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Constructor signature for creating a new OpenAlex client. Applies options in order; an option failure aborts with 'failed to apply option: '. Defaults: httpClient.Timeout 30s, baseURL https://api.openalex.org, userAgent openalex-go-client/1.0, email and apiKey empty. ```go func NewOpenAlexClient(opts ...OpenAlexOption) (*OpenAlexClient, error) ``` -------------------------------- ### Create a feature branch Source: https://github.com/dictybase/literature/blob/develop/README.md Command to create and switch to a new feature branch. ```bash git checkout -b feature/your-feature-name ``` -------------------------------- ### Fetch Article by DOI Source: https://github.com/dictybase/literature/blob/develop/README.md Retrieve an article directly using its DOI identifier after initializing the client. ```go client, err := literature.NewEuropePMCClient() if err != nil { log.Fatal(err) } // Fetch article directly by DOI article, err := client.GetArticleByDOI("10.1038/nature12373") if err != nil { log.Fatal(err) } fmt.Printf("Title: %s\n", article.Title) fmt.Printf("PMID: %s\n", article.PMID) fmt.Printf("DOI: %s\n", article.DOI) ``` -------------------------------- ### Fetch EuropePMC Article Source: https://github.com/dictybase/literature/blob/develop/README.md Initialize an EuropePMC client to retrieve articles by PMID or DOI, including rich metadata like citations and author affiliations. ```go package main import ( "fmt" "log" "github.com/dictybase/literature" ) func main() { // Create an EuropePMC client for rich metadata and European content client, err := literature.NewEuropePMCClient() if err != nil { log.Fatal(err) } // Fetch an article with enhanced metadata by PMID article, err := client.GetArticle("12345678") if err != nil { log.Fatal(err) } fmt.Printf("Title: %s\n", article.Title) fmt.Printf("Journal: %s\n", article.Journal.Title) fmt.Printf("Citations: %d\n", article.CitedByCount) fmt.Printf("Open Access: %t\n", article.IsOpenAccess) // Alternatively, fetch directly by DOI articleByDOI, err := client.GetArticleByDOI("10.1038/nature12373") if err != nil { log.Fatal(err) } fmt.Printf("\nArticle by DOI: %s\n", articleByDOI.Title) // Show author affiliations (EuropePMC-specific feature) for _, author := range article.Authors { fmt.Printf("Author: %s\n", author.FullName) for _, affiliation := range author.Affiliations { fmt.Printf(" - %s\n", affiliation.Affiliation) } } } ``` -------------------------------- ### New Client Source: https://github.com/dictybase/literature/blob/develop/README.md Creates a new literature client with customizable options for timeout, user agent, and HTTP client. ```APIDOC ## New Client ### Description Creates a new literature client with customizable options. ### Method New ### Parameters - **options** (variadic Option) - Optional configuration options. ### Request Example ```go client, err := literature.New( literature.WithTimeout(60*time.Second), literature.WithUserAgent("MyApp/1.0"), literature.WithHTTPClient(customHTTPClient), ) ``` ### Response Returns a new client and an error if initialization fails. ``` -------------------------------- ### Configuration Options Source: https://github.com/dictybase/literature/blob/develop/README.md Options for customizing the literature client. ```APIDOC ## Configuration Options ### Description Options for customizing the literature client. ### Options - **WithHTTPClient(client *http.Client)** - Custom HTTP client - **WithTimeout(timeout time.Duration)** - Request timeout - **WithBaseURL(url string)** - Custom API base URL (for testing) - **WithUserAgent(userAgent string)** - Custom User-Agent header - **WithAPIKey(apiKey string)** - Send your own NCBI API key as `api_key`; no key is bundled - **WithTool(tool string)** - Identify your application; value must contain no spaces - **WithEmail(email string)** - Send a valid developer contact email ``` -------------------------------- ### Configure PubMed Client Source: https://github.com/dictybase/literature/blob/develop/README.md Customize the literature client with timeout, user agent, and custom HTTP client settings. ```go client, err := literature.New( literature.WithTimeout(60*time.Second), literature.WithUserAgent("MyApp/1.0"), literature.WithHTTPClient(customHTTPClient), ) ``` -------------------------------- ### NewOpenAlexClient Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Creates a new OpenAlex client with configurable options. Applies defaults for timeout, base URL, user agent, email, and API key before applying provided options. ```APIDOC ## NewOpenAlexClient ### Description Creates a new OpenAlex client and applies options in order. An option failure aborts with `failed to apply option: `. ### Method Constructor ### Signature ```go func NewOpenAlexClient(opts ...OpenAlexOption) (*OpenAlexClient, error) ``` ### Parameters #### Options - **opts** (OpenAlexOption) - Optional - Options to configure the client. ### Defaults | Setting | Default | |---------|---------| | `httpClient.Timeout` | `30 * time.Second` | | `baseURL` | `https://api.openalex.org` | | `userAgent` | `openalex-go-client/1.0` | | `email` | `""` (Polite Pool off) | | `apiKey` | `""` | ### Request Example ```go client, err := literature.NewOpenAlexClient( literature.WithOpenAlexEmail("you@example.org"), ) if err != nil { log.Fatal(err) } ``` ### Response #### Success Response Returns a pointer to an `OpenAlexClient` and `nil` error. #### Error Response Returns `nil` client and an error if an option fails. ### Error Handling - **Throws:** error only if an `OpenAlexOption` fails. ``` -------------------------------- ### New Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/client.md Creates a new PubMed literature client with configurable options. Applies defaults for timeout, base URL, user agent, and identity settings before processing options. ```APIDOC ## New ### Description Creates a new PubMed literature client and applies the provided options in order. If any option returns an error, construction fails and returns a non-nil error wrapped with `failed to apply option: %w`. ### Method Constructor ### Signature `func New(opts ...Option) (*Client, error)` ### Parameters #### Options - `opts` (variadic Option) - Optional - Options to configure the client. ### Defaults | Setting | Default | |---------|---------| | `httpClient.Timeout` | `30 * time.Second` | | `baseURL` | `https://eutils.ncbi.nlm.nih.gov/entrez/eutils` | | `userAgent` | `literature-go-client/1.0` | | `apiKey` | `""` | | `tool` | `""` | | `email` | `""` | ### Request Example ```go client, err := literature.New( literature.WithTimeout(60*time.Second), literature.WithUserAgent("MyApp/1.0"), literature.WithAPIKey(os.Getenv("NCBI_API_KEY")), literature.WithTool("my-tool"), literature.WithEmail(os.Getenv("NCBI_EMAIL")), ) if err != nil { log.Fatal(err) } ``` ### Response #### Success Response Returns a `*Client` ready for use. #### Error Response Returns an error if an option fails (e.g., `WithTool` with spaces, or `WithEmail` with an invalid address), wrapped as `failed to apply option: `. ``` -------------------------------- ### Configure OpenAlex Client Source: https://github.com/dictybase/literature/blob/develop/README.md Customize the OpenAlex client using functional options. Providing an API key enables premium features and ensures it is redacted from error logs. ```go client, err := literature.NewOpenAlexClient( literature.WithOpenAlexEmail("contact@myapp.com"), // "Polite Pool" (free, faster) literature.WithOpenAlexAPIKey("your-api-key"), // OpenAlex Premium literature.WithOpenAlexTimeout(60*time.Second), literature.WithOpenAlexUserAgent("MyApp/1.0"), ) ``` -------------------------------- ### Resolve Identifiers with OpenAlex Source: https://github.com/dictybase/literature/blob/develop/README.md Initialize the client and fetch a scholarly work using an OpenAlex ID, PMID, or DOI. ```go client, err := literature.NewOpenAlexClient( literature.WithOpenAlexEmail("research@university.edu"), ) if err != nil { log.Fatal(err) } // By OpenAlex ID, PMID, or DOI work, err := client.GetWork("W2100837269") // or client.GetWorkByPMID("12345678") // or client.GetWorkByDOI("10.1038/nature12373") if err != nil { log.Fatal(err) } fmt.Printf("Title: %s\n", work.Title) fmt.Printf("DOI: %s\n", work.DOI) fmt.Printf("Publication year: %d\n", work.PublicationYear) ``` -------------------------------- ### Client struct definition Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/client.md The internal structure of the Client, containing unexported service fields and configuration settings. ```go type Client struct { articleService *internal.ArticleService searchService *internal.SearchService pdfService *internal.PDFService httpClient *http.Client baseURL string userAgent string apiKey string tool string email string validate *validator.Validate } ``` -------------------------------- ### Retrieve Citation Metrics and Graphs Source: https://github.com/dictybase/literature/blob/develop/README.md Fetch citation impact metrics, resolve referenced works, and retrieve paginated citing works using search options. ```go // Citation impact metrics metrics, err := client.GetCitationMetrics("W2100837269") if err != nil { log.Fatal(err) } fmt.Printf("Cited by: %d, FWCI: %.2f\n", metrics.CitedByCount, metrics.FWCI) fmt.Printf("Percentiles (min/max): %.2f / %.2f\n", metrics.PercentileMin, metrics.PercentileMax) // All works cited by the article (batched lookups) referenced, err := client.GetReferencedWorks("W2100837269") if err != nil { log.Fatal(err) } fmt.Printf("Cites %d works\n", len(referenced)) // One page of citing works, paginated by cursor citing, err := client.GetCitingWorks( "W2100837269", literature.WithOpenAlexPerPage(25), literature.WithOpenAlexSort("cited_by_count:desc"), ) if err != nil { log.Fatal(err) } fmt.Printf("%d citing works, next cursor: %s\n", citing.TotalCount, citing.Cursor) ``` -------------------------------- ### DownloadPDF method usage Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/client.md Downloads a PDF for a given PMID to a specified file path. It includes error handling for cases where the PDF is not available. ```go if err := client.DownloadPDF("12345678", "article.pdf"); err != nil { if litErr, ok := err.(*literature.Error); ok { switch litErr.Type { case literature.ErrorTypePDFNotAvailable: fmt.Println("PDF not available") } return } log.Fatal(err) } ``` -------------------------------- ### EuropePMCAuthorAffiliation struct Source: https://github.com/dictybase/literature/blob/develop/_autodocs/types.md Represents the affiliation details for an author. ```go type EuropePMCAuthorAffiliation struct { Affiliation string `json:"affiliation"` } ``` -------------------------------- ### OpenAlexAward struct Source: https://github.com/dictybase/literature/blob/develop/_autodocs/types.md Represents funding award information. ```go type OpenAlexAward struct { Funder OpenAlexFunder `json:"funder"` AwardID string `json:"award_id,omitempty"` AwardAmount int `json:"award_amount,omitempty"` FundingYear int `json:"funding_year,omitempty"` } ``` -------------------------------- ### EuropePMCFullTextURL struct Source: https://github.com/dictybase/literature/blob/develop/_autodocs/types.md Defines the URL and availability information for full-text documents associated with an article. ```go type EuropePMCFullTextURL struct { Availability string `json:"availability"` AvailabilityCode string `json:"availability_code"` DocumentStyle string `json:"document_style"` Site string `json:"site"` URL string `json:"url"` } ``` -------------------------------- ### Project Directory Structure Source: https://github.com/dictybase/literature/blob/develop/README.md Overview of the file and directory layout for the literature project. ```text literature/ ├── doc.go # Package documentation ├── literature.go # Main PubMed client interface ├── europepmc.go # EuropePMC client interface ├── openalex.go # OpenAlex client interface ├── types.go # PubMed data structures ├── europepmc_types.go # EuropePMC data structures ├── openalex_types.go # OpenAlex data structures ├── options.go # PubMed configuration options ├── europepmc_options.go # EuropePMC configuration options ├── openalex_options.go # OpenAlex configuration options ├── errors.go # Error types and handling ├── adapters.go # Internal service adapters ├── internal/ # Private implementation details │ ├── pubmed_service.go # PubMed API client │ ├── europepmc_service.go # EuropePMC API client │ └── openalex_service.go # OpenAlex API client ├── examples/ # Usage examples │ ├── basic/ # Basic PubMed examples │ ├── advanced/ # Advanced PubMed examples │ ├── europepmc/ # EuropePMC examples │ └── openalex/ # OpenAlex examples ├── testdata/ # Test fixtures └── cmd/pubmed/ # CLI tool (optional) ``` -------------------------------- ### EuropePMCGrant struct Source: https://github.com/dictybase/literature/blob/develop/_autodocs/types.md Defines the grant information structure in europepmc_types.go. ```go type EuropePMCGrant struct { GrantID string `json:"grant_id"` Agency string `json:"agency"` OrderIn int `json:"order_in"` } ``` -------------------------------- ### Access PDF and Full Text URLs Source: https://github.com/dictybase/literature/blob/develop/README.md Checks for PDF availability for a given PMID and retrieves the list of available PDF source URLs. ```go client, err := literature.NewEuropePMCClient() if err != nil { log.Fatal(err) } pmid := "25844567" // Check if PDF is available hasPDF, err := client.HasPDF(pmid) if err != nil { log.Fatal(err) } if hasPDF { // Get all available PDF URLs pdfURLs, err := client.GetPDFURLs(pmid) if err != nil { log.Fatal(err) } fmt.Printf("Available PDF sources for PMID %s:\n", pmid) for _, pdfURL := range pdfURLs { fmt.Printf(" - %s: %s\n", pdfURL.Site, pdfURL.URL) fmt.Printf(" Availability: %s (%s)\n", pdfURL.Availability, pdfURL.AvailabilityCode) } } else { fmt.Printf("No PDF available for PMID %s\n", pmid) } ``` -------------------------------- ### lit-cli usage and options Source: https://github.com/dictybase/literature/blob/develop/examples/cli-tool/README.md Command-line usage, options, and exit codes for lit-cli. The -o flag sets the output PDF filename (default: .pdf), and -h shows help. Exit codes: 0 for success, 1 for missing identifier, article not found, or download failure. ```text lit-cli [OPTIONS] OPTIONS: -o, --output FILE Output filename for PDF [default: .pdf] -h, --help Show help and exit EXIT CODES: 0 Success 1 Missing identifier, article not found, or download failed ``` -------------------------------- ### OpenAlexTopic struct Source: https://github.com/dictybase/literature/blob/develop/_autodocs/types.md Represents a research topic. The hierarchy follows Domain → Field → Subfield → Topic. ```go type OpenAlexTopic struct { OpenAlexID string `json:"openalex_id,omitempty"` DisplayName string `json:"display_name"` Score float64 `json:"score"` Subfield OpenAlexTaxon `json:"subfield,omitempty"` Field OpenAlexTaxon `json:"field,omitempty"` Domain OpenAlexTaxon `json:"domain,omitempty"` } ``` -------------------------------- ### Handle EuropePMC Errors Source: https://github.com/dictybase/literature/blob/develop/README.md Demonstrates how to type-assert errors to the literature.Error type to handle specific API error scenarios. ```go article, err := client.GetArticle("invalid-pmid") if err != nil { if litErr, ok := err.(*literature.Error); ok { switch litErr.Type { case literature.ErrorTypeInvalidInput: fmt.Println("Invalid PMID format") case literature.ErrorTypeArticleNotFound: fmt.Println("Article not found in EuropePMC") case literature.ErrorTypeAPIError: fmt.Printf("EuropePMC API error: %s\n", litErr.Message) case literature.ErrorTypeNetworkError: fmt.Println("Network error - check connection") } } } ``` -------------------------------- ### OpenAlexFunder struct Source: https://github.com/dictybase/literature/blob/develop/_autodocs/types.md Represents a funding organization. ```go type OpenAlexFunder struct { OpenAlexID string `json:"openalex_id,omitempty"` DisplayName string `json:"display_name"` } ``` -------------------------------- ### OpenAlexLocation struct Source: https://github.com/dictybase/literature/blob/develop/_autodocs/types.md Defines the location metadata structure in openalex_types.go. ```go type OpenAlexLocation struct { LandingPageURL string `json:"landing_page_url,omitempty"` PDFURL string `json:"pdf_url,omitempty"` License string `json:"license,omitempty"` Version string `json:"version,omitempty"` Source OpenAlexSource `json:"source,omitempty"` } ``` -------------------------------- ### OALink struct definition Source: https://github.com/dictybase/literature/blob/develop/README.md Represents a link with format and href attributes. ```go type OALink struct { Format string `xml:"format,attr"` HREF string `xml:"href,attr"` } ``` -------------------------------- ### OpenAlexKeyword struct Source: https://github.com/dictybase/literature/blob/develop/_autodocs/types.md Represents a keyword associated with a work. ```go type OpenAlexKeyword struct { OpenAlexID string `json:"openalex_id,omitempty"` DisplayName string `json:"display_name"` Score float64 `json:"score"` } ``` -------------------------------- ### OpenAlexClient struct definition Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Defines the OpenAlexClient struct with unexported fields for the internal service, HTTP client, base URL, user agent, email, API key, and validator. Instances are created via NewOpenAlexClient. ```go type OpenAlexClient struct { openAlexService *internal.OpenAlexService httpClient *http.Client baseURL string userAgent string email string apiKey string validate *validator.Validate } ``` -------------------------------- ### Error constructors Source: https://github.com/dictybase/literature/blob/develop/_autodocs/errors.md Constructors for creating new Error instances with various context fields. ```APIDOC ## Error constructors ### Description Constructors for creating new Error instances with various context fields. ### Functions - `func NewError(errorType ErrorType, message string) *Error` - `func NewErrorWithPMID(errorType ErrorType, pmid, message string) *Error` - `func NewErrorWithQuery(errorType ErrorType, query, message string) *Error` - `func NewErrorWithDOI(errorType ErrorType, doi, message string) *Error` - `func WrapError(errorType ErrorType, message string, cause error) *Error` - `func WrapErrorWithPMID(errorType ErrorType, pmid, message string, cause error) *Error` - `func WrapErrorWithDOI(errorType ErrorType, doi, message string, cause error) *Error` `Wrap*` variants also set `Cause`; `NewError*` variants set `PMID`/`Query`/`DOI` context fields. ``` -------------------------------- ### GetCitationMetrics(workID string) (*CitationMetrics, error) Source: https://github.com/dictybase/literature/blob/develop/_autodocs/api-reference/openalex-client.md Returns citation count, FWCI, and normalized percentiles for a work. Fetches the work and extracts the metrics from it. ```APIDOC ## GetCitationMetrics(workID string) (*CitationMetrics, error) ### Description Returns citation count, FWCI, and normalized percentiles for a work. Fetches the work and extracts the metrics from it. ### Method Function call on OpenAlexClient ### Parameters - **workID** (string) - Required - Work identifier ### Request Example ```go metrics, err := client.GetCitationMetrics("W2100837269") if err != nil { log.Fatal(err) } fmt.Printf("Cited by %d, FWCI %.2f, percentiles %.2f-%.2f\n", metrics.CitedByCount, metrics.FWCI, metrics.PercentileMin, metrics.PercentileMax) ``` ### Response Returns *CitationMetrics. Throws *Error from GetWork. ```