ArxivKit is a Swift DSL wrapper for arXiv API. It includes an embedded Domain-specific language for constructing arXiv queries in a type-safe way. For detailed explanation of all the available APIs see project documentation page.
This project is not affiliated with arXiv.org.
Minimal version of Swift required for building the package is 5.3. Following platforms are supported:
- macOS (from v11.0)
- iOS, iPadOS, Mac Catalyst (from v14.0)
- Linux (tested on Ubuntu 20.04)
To use in an Xcode project, add https://github.com/ivicamil/ArxivKit.git
as package dependency as explained in Apple developer documentation.
In package-based projects, add ArxivKit
dependency to Package.swift
as explained bellow:
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "ProjectName",
platforms: [],
dependencies: [
// Replace the version string with your own desired minimal version.
.package(url: "https://github.com/ivicamil/ArxivKit.git", from: "2.0.0")
],
targets: [
.target(
name: "ProjectName",
dependencies: ["ArxivKit"])
]
)
ArxivKit
uses URLSession
for sending API requests. It is strongly recommended to reuse a single session instance for multiple related tasks. For detailed information about creating, configuring and using URLSession
and related APIs see Apple Developer documentation for the class. In many cases, including all the examples from this document, a session with default configuration is enough:
let session = URLSession(configuration: .default)
or
let session = URLSession(configuration: .default, delegate: nil, delegateQueue: .main)
ArxivKit
defines convenience extension methods on URLSession
and ArxivRequest
that create URLSessionDataTask
for sending arXiv API requests and parsing received response. In more advanced cases, clients can implement their own custom networking layer and still use this library as a Domain Specific Language for constructing ArxivRequest
values. In that case, ArxivParser
can be used for parsing raw API responses to ArxivReponse
values.
ArxivQuery
type specifies different possible information that can be searched on arXiv. ArxivQuery
conforms to ArxivRequest
protocol and it can be used to create and run fetch tasks. Before fetching, an ArxivRequest
can be configured with various modifier methods to define desired number of articles per page, sorting order and criterion etc.
ArxivKit
enables construction of all the search queries available in Arxiv API. Articles can be searched for a term in any of the available fields, by arXiv subject or by publication and update dates. All the subjects are available as constants under following namespaces:
Physics
Astrophysics
CondensedMatter
NonlinearSciences
OtherPhysicsSubjects
Mathematics
ComputerScience
QuantitativeBiology
ElectricalEngineeringAndSystemsScience
Statistics
QuantitativeFinance
Economy
Queries are constructed by using an embedded Domain Specific Language created with Swift feature called Result Builders, that was first used in Apple's SwiftUI Framework. The DSL enables creating arbitrarily complex query trees by using an intuitive syntax.
After a query is constructed and configured, fetch(using:completion:)
or other related methods can be used to construct and run a fetch task. If no error occurs, fetch task returns an ArxivResponse
, a parsed arXiv API atom feed. The response stores various metadata and a list of ArxivEntry
values. Each entry stores information about a single arXiv article, such as its title, abstract, authors, PDF link etc.
Bellow are the examples of few common use scenarios.
do {
let response = try await term("electron").fetch(using: session)
let articles = response.entries
print("Found \(response.totalResults) articles")
print()
print(articles.map { $0.title }.joined(separator: "\n\n"))
} catch {
print("Could not fetch articles: \(error.localizedDescription)")
}
term("electron").fetch(using: session) { result in
switch result {
case let .success(response):
let articles = response.entries
print("Found \(response.totalResults) articles")
print()
print(articles.map { $0.title }.joined(separator: "\n\n"))
case let .failure(error):
print("Could not fetch articles: \(error.localizedDescription)")
}
}
term("dft")
term("dft", in: .title)
term("dft", in: .abstract)
term("Feynman", in: .authors)
term("20 pages", in: .comment)
term("AMS", in: .journalReference)
subject(Physics.computationalPhysics)
submitted(in: .past(.month))
lastUpdated(in: .past(5, unit: .day))
all {
any {
term("dft", in: .title)
term(#""ab initio""#, in: .title)
}
subject(Physics.computationalPhysics)
}
.excluding {
term("conductivity", in: .title)
}
ArxivIdList("2101.02212", "2101.02215")
.fetch(using: session) { result in
// Do something with the result
}
let entry: ArxivEntry = ...
ArxivIdList(ids: entry.allVersionsIDs)
.fetch(using: session) { result in
// Do something with the result
}
var currentResponse: ArxivResponse?
func fetchElectronArticles(startIndex i: Int) {
term("electron")
.itemsPerPage(20)
.startIndex(i)
.fetch(using: session) { result in
switch result {
case let .success(response):
currentResponse = response
print("Page \(response.currentPage) fetched.")
case let .failure(error):
// Deal with error
}
}
}
// Fetch the first page
fetchElectronArticles(startIndex: 0)
// When we are sure that the first page is fetched, we can fetch the second page
if let response = currentResponse, let secondPageIndex = response.nextPageStartIndex {
fetchElectronArticles(startIndex: secondPageIndex)
}
term("electron")
.sorted(by: .relevance)
.sortingOrder(.descending)
.itemsPerPage(20)
.startIndex(60)
.fetch(using: session) { result in
// Do something with the result
}
On Apple platforms, Combine framework can be used for advanced processing of URL Session data task results, as explained in this Apple Developer Documentation article. ArxivKit
works naturally with Combine
. Bellow is a simple example of creating a publisher for receiving arXiv API results and subscribing to it:
import Combine
var cancelable: AnyCancellable?
cancelable = session
.dataTaskPublisher(for: term("electronic configuration").url)
.tryMap(ArxivParser().parse)
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { completion in
let outcome: String
switch completion {
case .finished:
outcome = "successfully"
case let .failure(error):
outcome = "with error: \(error)"
}
print("Publisher completed \(outcome).")
},
receiveValue: { response in
print ("Received arXiv feed:\n\n \(response)\n")
}
)
ArxivKit
is released under MIT license. For terms and conditions of using the arXiv API itself see arXiv API Help.