
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@api-platform/ld
Advanced tools
Rich JSON formats such as JSON-LD use IRIs to reference embeded data. This library fetches the wanted Linked Data automatically.
I have an API referencing books and their authors, GET /books/1 returns:
{
"@id": "/books/1",
"@type": ["https://schema.org/Book"],
"title": "Hyperion",
"author": "https://localhost/authors/1"
}
Thanks to @api-platform/ld you can load authors automatically when you need them:
import ld from '@api-platform/ld'
const pattern = new URLPattern("/authors/:id", "https://localhost");
const books = await ld('/books', {
urlPattern: pattern,
onUpdate: (newBooks) => {
log()
}
})
function log() {
console.log(books.author?.name)
}
log()
npm install @api-platform/ld
Use ld like fetch and specify the URLPattern to match IRIs that are going to be fetched automatically:
import ld from '@api-platform/ld'
await ld('/books', {urlPattern: new URLPattern("/authors/:id", "https://localhost")})
Available options:
fetchFn fetch function, defaults to fetch().then((res) => res.json())urlPattern the url pattern filterrelativeURIs supports relative URIs (defaults to true)onUpdate: (root, options: { iri: string, data: any }) callback on data updateonError error callback on fetch errorsURLPattern is available as a polyfil at https://www.npmjs.com/package/urlpattern-polyfill
import ld from "@api-platform/ld";
import {useEffect} from "react"
import {createRoot} from "react-dom/client"
import {
QueryClient,
useQuery,
QueryClientProvider,
} from '@tanstack/react-query'
const queryClient = new QueryClient();
const pattern = new URLPattern("/(books|authors)/:id", window.origin);
function Books() {
const {isPending, error, data: books} = useQuery({
queryKey: ['/books'],
notifyOnChangeProps: 'all',
queryFn: ({queryKey}) => ld(queryKey, {
urlPattern: pattern,
onUpdate: (root, {iri, data}) => {
queryClient.setQueryData(queryKey, root)
}
})
})
if (isPending) return 'Loading...'
if (error) return 'An error has occurred: ' + error.message
return (
<ul>
{books.member.map(b => (<li data-testid="book">{b?.title} - {b?.author?.name}</li>))}
</ul>
);
}
function App() {
return (
<QueryClientProvider client={queryClient}>
<Books />
</QueryClientProvider>
)
}
createRoot(root).render(<App />)
import { useState, useEffect } from "react";
import { createRoot } from "react-dom/client";
import ld from "@api-platform/ld";
function App() {
const pattern = new URLPattern("/(books|authors)/:id", window.origin);
const [books, setBooks] = useState({});
useEffect(() => {
let ignore = false;
setBooks({});
ld('/books', {onUpdate: (books) => setBooks(books), urlPattern: pattern})
.then(books => {
if (!ignore) {
setBooks(books);
}
});
return () => {
ignore = true;
};
}, []);
return (
<ul>
{books.member?.map(b => (<li data-testid="book">{b.title} - {b.author?.name}</li>))}
</ul>
);
}
const root = createRoot(document.getElementById("root"));
root.render(<App />);
import ld from "@api-platform/ld";
const pattern = new URLPattern("/(books|authors)/:id", window.origin);
const list = document.getElementById('list')
function onUpdate(books) {
const l = []
books.member.forEach((book) => {
const li = document.createElement('li')
li.dataset.testid = 'book'
li.innerText = `${book.title} - ${book.author?.name}`
l.push(li)
});
list.replaceChildren(...l)
}
ld('/books', {urlPattern: pattern, onUpdate, fetchfn: (url, options) => axios.get(url)})
.then((books) => {
books.member.forEach((book) => {
const li = document.createElement('li')
li.dataset.testid = 'book'
li.innerText = `${book.title} - ${book.author?.name}`
list.appendChild(li)
});
})
import ld from "@api-platform/ld";
const pattern = new URLPattern("/(books|authors)/:id", window.origin);
const list = document.getElementById('list')
function onUpdate(books) {
const l = []
books.member.forEach((book) => {
const li = document.createElement('li')
li.dataset.testid = 'book'
li.innerText = `${book.title} - ${book.author?.name}`
l.push(li)
});
list.replaceChildren(...l)
}
ld('/books', {urlPattern: pattern, onUpdate})
.then((books) => {
books.member.forEach((book) => {
const li = document.createElement('li')
li.dataset.testid = 'book'
li.innerText = `${book.title} - ${book.author?.name}`
list.appendChild(li)
});
})
Example of a SWR hook:
import ld, { LdOptions } from '@api-platform/ld'
import useSWR from 'swr'
import {useState} from 'react'
import type { SWRConfiguration, KeyedMutator } from 'swr'
export type fetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
export type Fetcher = (...args: any[]) => Promise<any>
export type onUpdateCallback<T> = (root: T, options: { iri: string, data: object }) => void;
export default function useSWRLd<T extends object>(url: string, fetcher: Fetcher, config: Partial<LdOptions<T>> & SWRConfiguration = {}) {
let cb: undefined | KeyedMutator<T> = undefined
// You may need to force re-rendering as the comparison algorithm of SWR does not work well when object keys are added
// another solution is to improve the compare function
const [, setRender] = useState(false)
const res = useSWR(
url,
(url: RequestInfo | URL, opts: RequestInit) =>
ld(url, {
...opts,
fetchFn: fetcher,
urlPattern: config.urlPattern,
onUpdate: (root) => {
if (cb) {
cb(root, { optimisticData: root, revalidate: false })
setRender((s: boolean) => !s)
}
},
relativeURIs: config.relativeURIs,
onError: config.onError,
}),
config
);
cb = res.mutate
return res
}
FAQs
Fetch Edge Side APIs
The npm package @api-platform/ld receives a total of 15 weekly downloads. As such, @api-platform/ld popularity was classified as not popular.
We found that @api-platform/ld demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.