npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ministerjs/resource

v2.0.0

Published

Um pacote TypeScript para padronização de APIs REST, fornecendo uma interface consistente para operações CRUD com suporte a filtros, paginação e relacionamentos parent-child.

Readme

@ministerjs/resource

Um pacote TypeScript para padronização de APIs REST, fornecendo uma interface consistente para operações CRUD com suporte a filtros, paginação e relacionamentos parent-child.

📦 Instalação

npm install @ministerjs/resource
# ou
pnpm add @ministerjs/resource
# ou
yarn add @ministerjs/resource

🚀 Uso Básico

import { useRestResources } from "@ministerjs/resource";

// Configurar o gerenciador de recursos
const resources = useRestResources(fetch);

// Obter um recurso específico
const usersResource = resources.get<User>("users");

// Usar operações CRUD
const users = await usersResource.list();
const user = await usersResource.get(1);
const newUser = await usersResource.create({
  name: "João",
  email: "[email protected]",
});

📚 API Reference

Métodos Disponíveis

get(id?: string | number)

Busca um item específico ou o primeiro item se nenhum ID for fornecido.

Request:

GET /{resource}
GET /{resource}/{id}

Response:

{
  data: T;
  parents?: Record<string, ResourceItem>;
  children?: Record<string, ResourceItem>;
}

Exemplo:

// Buscar usuário específico
const user = await usersResource.get(123);

// Buscar primeiro usuário
const firstUser = await usersResource.get();

getByProperty<K>(key: K, value: T[K])

Busca um item por uma propriedade específica.

Request:

GET /{resource}/{key}/{value}

Response:

{
  data: T;
  parents?: Record<string, ResourceItem>;
  children?: Record<string, ResourceItem>;
}

Exemplo:

// Buscar usuário por email
const user = await usersResource.getByProperty("email", "[email protected]");

// Buscar produto por SKU
const product = await productsResource.getByProperty("sku", "ABC123");

list(options?: ListQuery<T>)

Lista itens com suporte a filtros, busca, paginação e ordenação.

Request:

GET /{resource}?page=1&resultsPerPage=10&search=termo&sort=name:asc&filters=status:active

Parâmetros de Query:

| Parâmetro | Tipo | Descrição | | ---------------- | -------------------------------- | ---------------------------------------------------- | | fields | BooleanDict<keyof T> | Campos que serão retornados | | search | string | Termo de busca | | page | number | Número da página (padrão: 1) | | resultsPerPage | number | Itens por página (padrão: 10) | | sort | SortSet | Ordenação (ex: "name:asc,created_at:desc") | | filters | FilterSet | Filtros por campo (ex: "status:active,type:premium") | | parent | Pair<string, string \| number> | Relacionamento parent-child |

Response:

{
  data: T[];
  pageInfo: {
    page: number;
    totalResults: number;
    resultsPerPage: number;
  };
}

Exemplo:

// Listagem básica
const users = await usersResource.list();

// Com filtros e paginação
const activeUsers = await usersResource.list({
  page: 2,
  resultsPerPage: 20,
  search: "João",
  sort: "name:asc,created_at:desc",
  filters: "status:active,role:admin",
  fields: { id: true, name: true, email: true },
});

// Com relacionamento parent
const userPosts = await postsResource.list({
  parent: ["user_id", 123],
});

create(data: Partial<T> | FormData, options?: CreateQuery)

Cria um novo item.

Request:

POST /{resource}
Content-Type: application/json

Body:

{
  "name": "João Silva",
  "email": "[email protected]",
  "role": "admin"
}

Response:

{
  message: string;
  data: T;
}

Exemplo:

// Criar usuário com JSON
const newUser = await usersResource.create({
  name: "João Silva",
  email: "[email protected]",
  role: "admin",
});

// Criar com FormData (para uploads)
const formData = new FormData();
formData.append("name", "João");
formData.append("avatar", file);

const userWithAvatar = await usersResource.create(formData);

// Criar com relacionamento parent
const newPost = await postsResource.create(
  {
    title: "Meu Post",
    content: "Conteúdo do post",
  },
  {
    parent: ["user_id", 123],
  },
);

update(id: string | number, data: Partial<T> | FormData)

Atualiza um item existente.

Request:

PUT /{resource}/{id}
Content-Type: application/json

Body:

{
  "name": "João Silva Santos",
  "email": "[email protected]"
}

Response:

{
  message: string;
  data: T;
}

Exemplo:

// Atualizar usuário
const updatedUser = await usersResource.update(123, {
  name: "João Silva Santos",
  email: "[email protected]",
});

// Atualizar com FormData
const formData = new FormData();
formData.append("avatar", newAvatarFile);

const userWithNewAvatar = await usersResource.update(123, formData);

updateProperty<K>(id: string | number, key: K, value: Partial<T>[K])

Atualiza uma propriedade específica de um item.

Request:

PUT /{resource}/{id}/{property}
Content-Type: application/json

Body:

"novo_valor"

Response:

{
  message: string;
  data: T;
}

Exemplo:

// Atualizar apenas o status do usuário
const user = await usersResource.updateProperty(123, "status", "inactive");

// Atualizar apenas o email
const user = await usersResource.updateProperty(123, "email", "[email protected]");

updateObject(data: Partial<T> | FormData)

Atualiza o objeto atual sem especificar ID (útil para contextos onde o ID é implícito).

Request:

PUT /{resource}
Content-Type: application/json

Body:

{
  "name": "Novo Nome",
  "email": "[email protected]"
}

Response:

{
  message: string;
  data: T;
}

Exemplo:

// Atualizar objeto no contexto atual
const updatedItem = await usersResource.updateObject({
  name: "Novo Nome",
  preferences: { theme: "dark" },
});

updatePropertyMany<K>(key: K, data: Pick<T, "id" | K>[])

Atualiza uma propriedade específica em múltiplos itens.

Request:

PUT /{resource}/{property}
Content-Type: application/json

Body:

[
  { "id": 1, "status": "active" },
  { "id": 2, "status": "inactive" },
  { "id": 3, "status": "active" }
]

Response:

{
  message: string;
  data: T[];
}

Exemplo:

// Atualizar status de múltiplos usuários
const updatedUsers = await usersResource.updatePropertyMany("status", [
  { id: 1, status: "active" },
  { id: 2, status: "inactive" },
  { id: 3, status: "pending" },
]);

// Atualizar categoria de múltiplos produtos
const updatedProducts = await productsResource.updatePropertyMany("category", [
  { id: 101, category: "electronics" },
  { id: 102, category: "books" },
  { id: 103, category: "clothing" },
]);

delete(id: string | number)

Remove um item.

Request:

DELETE /{resource}/{id}

Response:

{
  message: string;
}

Exemplo:

// Deletar usuário
await usersResource.delete(123);

// Deletar produto
await productsResource.delete("ABC123");

🔧 Configuração Avançada

Custom Fetch

Você pode fornecer sua própria implementação de fetch para adicionar headers, autenticação, etc:

// Fetch customizado com autenticação
const customFetch = async (url: string, options: RequestInit) => {
  return fetch(url, {
    ...options,
    headers: {
      ...options?.headers,
      Authorization: `Bearer ${getToken()}`,
      "Content-Type": "application/json",
    },
  });
};

const resources = useRestResources(customFetch);

Tratamento de Erros

O pacote inclui tratamento de erros padronizado:

import { RequestError } from "@ministerjs/resource";

try {
  const user = await usersResource.get(999);
} catch (error) {
  if (error instanceof RequestError) {
    console.log("Erro da API:", error.message);
    console.log("Detalhes:", error.details);

    // Verificar erros de campo específico
    error.details?.forEach((detail) => {
      if (detail.domain === "field") {
        console.log(`Erro no campo ${detail.fieldkey}: ${detail.message}`);
      }
    });
  }
}

📝 Tipos TypeScript

O pacote é totalmente tipado com TypeScript. Principais interfaces:

// Item base do recurso
type ResourceItem = Record<string, any>;

// Resposta de item único
interface GettedItemResponse<T extends ResourceItem> {
  data: T;
  parents?: Record<string, ResourceItem>;
  children?: Record<string, ResourceItem>;
}

// Resposta de lista
interface ListedItemsResponse<T extends ResourceItem> {
  data: T[];
  pageInfo: {
    page: number;
    totalResults: number;
    resultsPerPage: number;
  };
}

// Resposta de erro
interface ResponseError {
  error: string;
  message: string;
  details?: {
    message: string;
    domain: "global" | "field";
    fieldkey?: string;
  }[];
}

🏗️ Integração com Framework MinisterJS

Este pacote faz parte do ecossistema MinisterJS e se integra perfeitamente com:

  • @ministerjs/server - Para implementação do backend
  • @ministerjs/utils - Para utilitários como FilterSet, SortSet
  • @ministerjs/composables - Para composables Vue.js

📄 Licença

Este pacote faz parte do framework MinisterJS (UNLICENSED).