
Security News
npm Adopts OIDC for Trusted Publishing in CI/CD Workflows
npm now supports Trusted Publishing with OIDC, enabling secure package publishing directly from CI/CD workflows without relying on long-lived tokens.
Zap Lang parser and validator - A human-friendly, JSON-based language for describing HTTP requests, collections, environments, and variables for API testing
A TypeScript utility library for parsing, validating, and transforming Zap Lang API collection files. It enables filesystem-first, portable, and human-readable API collections for use in VS Code, CLI, or browser-based API testing and automation tools.
api-collection
, api-folder
, api-request
, api-global
, api-environment
)items
arrays required; hierarchy is inferred from directory structuretype
field in request)npm install zap-lang
import { parseZap, validateZapObject } from 'zap-lang';
// Parse a Zap Lang file
const zapFileContent = `{
"zapType": "api-request",
"zapVersion": 1,
"meta": { "name": "Get Users" },
"request": {
"method": "GET",
"url": "{{baseUrl}}/users",
"headers": [
{ "name": "Authorization", "value": "Bearer {{token}}" }
]
}
}`;
const result = parseZap(zapFileContent);
if (result.validation.valid) {
console.log('Valid Zap request:', result.object);
} else {
console.error('Validation errors:', result.validation.errors);
}
import { mergeZapVariables } from 'zap-lang';
const variables = mergeZapVariables({
global: { zapType: 'api-global', zapVersion: 1, variables: { timeout: 5000 } },
environment: { zapType: 'api-environment', zapVersion: 1, variables: { baseUrl: 'https://api.dev.example.com' } },
collection: { zapType: 'api-collection', zapVersion: 1, meta: { name: 'Users' }, variables: { version: 'v1' } },
sessionVars: { token: 'abc123' }
});
// Result: { timeout: 5000, baseUrl: 'https://api.dev.example.com', version: 'v1', token: 'abc123' }
import { zapRequestToAxiosConfig } from 'zap-lang';
const zapRequest = {
zapType: 'api-request',
zapVersion: 1,
meta: { name: 'Create User' },
request: {
method: 'POST',
url: '{{baseUrl}}/users',
headers: [
{ name: 'Content-Type', value: 'application/json' },
{ name: 'Authorization', value: 'Bearer {{token}}' }
],
body: {
type: 'json',
content: '{"name": "{{userName}}", "email": "{{userEmail}}"}'
}
}
};
const variables = {
baseUrl: 'https://api.example.com',
token: 'abc123',
userName: 'John Doe',
userEmail: 'john@example.com'
};
const axiosConfig = zapRequestToAxiosConfig(zapRequest, variables);
// Result: Ready-to-use Axios config object
console.log(axiosConfig);
// {
// method: 'post',
// url: 'https://api.example.com/users',
// headers: {
// 'Content-Type': 'application/json',
// 'Authorization': 'Bearer abc123'
// },
// data: {
// name: 'John Doe',
// email: 'john@example.com'
// }
// }
import { loadZapFiles, getAllRequests, mergeZapVariables } from 'zap-lang';
// Load all .zap files from a directory structure
const files = loadZapFiles('./my-api-collection');
// Returns a flat object with all parsed .zap files keyed by relative path
// Get all requests from the loaded files
const requests = getAllRequests(files);
// Example: Execute all requests in a collection
for (const [path, request] of Object.entries(requests)) {
const variables = mergeZapVariables({
collection: files['collection.zap'],
request: request,
sessionVars: { token: 'your-token' }
});
const axiosConfig = zapRequestToAxiosConfig(request, variables);
// Execute with axios: await axios(axiosConfig)
}
parseZap(content: string): ZapParseResult
Parses a JSON string into a validated Zap object.
const result = parseZap('{"zapType": "api-request", ...}');
if (result.validation.valid) {
console.log(result.object); // Parsed Zap object
} else {
console.log(result.validation.errors); // Validation errors
}
Returns: { object: ZapObject | null, validation: ZapValidationResult }
serializeZap(obj: ZapObject, indent?: number): string
Serializes a Zap object to a JSON string.
const json = serializeZap(zapObject, 2); // Pretty-printed with 2-space indent
isValidZapString(content: string): boolean
Quick check if a string contains valid Zap Lang JSON.
if (isValidZapString(fileContent)) {
// Safe to parse
}
validateZapObject(obj: any): ZapValidationResult
Validates any object against Zap Lang schema.
const validation = validateZapObject(someObject);
if (validation.valid) {
// Object is valid
} else {
console.log(validation.errors); // Array of error messages
}
Returns: { valid: boolean, errors: string[] }
isValidZapObject(obj: any): boolean
Quick boolean check for object validity.
if (isValidZapObject(obj)) {
// Object is valid
}
createApiRequest(options: Partial<ZapApiRequest>): ZapApiRequest
Creates a new API request object with defaults.
const request = createApiRequest({
meta: { name: 'Get Users' },
request: {
method: 'GET',
url: '{{baseUrl}}/users'
}
});
createApiCollection(options: Partial<ZapApiCollection>): ZapApiCollection
Creates a new API collection object.
const collection = createApiCollection({
meta: { name: 'My API Collection' },
variables: { baseUrl: 'https://api.example.com' }
});
createApiFolder(options: Partial<ZapApiFolder>): ZapApiFolder
Creates a new API folder object.
const folder = createApiFolder({
meta: { name: 'User Management' },
variables: { endpoint: '/users' }
});
createApiEnvironment(options: Partial<ZapApiEnvironment>): ZapApiEnvironment
Creates a new environment object.
const env = createApiEnvironment({
meta: { name: 'Development' },
variables: { baseUrl: 'https://api.dev.example.com' }
});
createApiGlobal(options: Partial<ZapApiGlobal>): ZapApiGlobal
Creates a new global variables object.
const global = createApiGlobal({
variables: { timeout: 5000, retries: 3 }
});
mergeZapVariables(options: MergeVariablesOptions): Record<string, any>
Merges variables from all scopes with proper precedence.
const variables = mergeZapVariables({
global: globalVarsObject, // Lowest precedence
environment: environmentObject,
collection: collectionObject,
folder: folderObject,
request: requestObject,
sessionVars: { token: 'abc123' } // Highest precedence
});
Precedence (lowest to highest): global → environment → collection → folder → request → session
replaceVariables(template: string, variables: Record<string, any>): string
Replaces {{variable}}
placeholders in a string.
const url = replaceVariables('{{baseUrl}}/users/{{userId}}', {
baseUrl: 'https://api.example.com',
userId: '123'
});
// Result: 'https://api.example.com/users/123'
extractVariables(template: string): string[]
Extracts variable names from a template string.
const vars = extractVariables('{{baseUrl}}/users/{{userId}}');
// Result: ['baseUrl', 'userId']
loadZapFiles(directory: string): Record<string, ZapObject>
Loads all .zap files from a directory tree.
const files = loadZapFiles('./my-collection');
// Result: { 'folder/request.zap': requestObject, ... }
filterZapObjectsByType<T>(objects: Record<string, ZapObject>, zapType: ZapType): Record<string, T>
Filters loaded objects by type.
const requests = filterZapObjectsByType(files, 'api-request');
const collections = filterZapObjectsByType(files, 'api-collection');
findCollectionRoot(objects: Record<string, ZapObject>): ZapApiCollection | null
Finds the root collection object.
const rootCollection = findCollectionRoot(files);
getAllRequests(objects: Record<string, ZapObject>): Record<string, ZapApiRequest>
Gets all request objects from loaded files.
const requests = getAllRequests(files);
getAllFolders(objects: Record<string, ZapObject>): Record<string, ZapApiFolder>
Gets all folder objects from loaded files.
const folders = getAllFolders(files);
getEnvironments(objects: Record<string, ZapObject>): Record<string, ZapApiEnvironment>
Gets all environment objects.
const environments = getEnvironments(files);
getGlobalVariables(objects: Record<string, ZapObject>): ZapApiGlobal | null
Gets the global variables object.
const global = getGlobalVariables(files);
findAllRequests(obj: ZapObject): ZapApiRequest[]
Recursively finds all requests within a collection or folder.
const requests = findAllRequests(collectionObject);
zapRequestToAxiosConfig(zapRequest: ZapApiRequest, variables: Record<string, any>): AxiosRequestConfig
Converts a Zap request to an Axios-compatible configuration object.
const axiosConfig = zapRequestToAxiosConfig(zapRequest, variables);
// Use with axios: axios(axiosConfig)
Features:
ZAP_LANG_VERSION: string
The current version of this zap-lang package.
ZAP_SPEC_VERSION: number
The Zap Lang specification version supported (currently 1).
import {
loadZapFiles,
getAllRequests,
mergeZapVariables,
zapRequestToAxiosConfig,
getEnvironments,
getGlobalVariables
} from 'zap-lang';
import axios from 'axios';
// 1. Load collection from filesystem
const files = loadZapFiles('./my-api-collection');
// 2. Get environment and global variables
const environments = getEnvironments(files);
const global = getGlobalVariables(files);
const environment = environments['development.zap']; // or user selection
// 3. Get all requests
const requests = getAllRequests(files);
// 4. Execute a specific request
async function executeRequest(requestPath: string, sessionVars: Record<string, any> = {}) {
const request = requests[requestPath];
if (!request) throw new Error(`Request not found: ${requestPath}`);
// Merge variables from all scopes
const variables = mergeZapVariables({
global,
environment,
collection: files['collection.zap'],
request,
sessionVars
});
// Convert to axios config
const axiosConfig = zapRequestToAxiosConfig(request, variables);
// Execute the request
try {
const response = await axios(axiosConfig);
console.log(`✅ ${request.meta.name}:`, response.status, response.data);
return response;
} catch (error) {
console.error(`❌ ${request.meta.name}:`, error.message);
throw error;
}
}
// Execute requests
await executeRequest('users/create-user.zap', {
userName: 'John Doe',
userEmail: 'john@example.com'
});
import {
createApiCollection,
createApiFolder,
createApiRequest,
serializeZap
} from 'zap-lang';
// Create a new collection
const collection = createApiCollection({
meta: {
name: 'Users API',
description: 'CRUD operations for user management'
},
variables: {
baseUrl: 'https://api.example.com',
version: 'v1'
}
});
// Create a folder
const usersFolder = createApiFolder({
meta: { name: 'User Operations' },
variables: { endpoint: '/users' }
});
// Create requests
const createUserRequest = createApiRequest({
meta: { name: 'Create User' },
request: {
method: 'POST',
url: '{{baseUrl}}/{{version}}{{endpoint}}',
headers: [
{ name: 'Content-Type', value: 'application/json' },
{ name: 'Authorization', value: 'Bearer {{token}}' }
],
body: {
type: 'json',
content: JSON.stringify({
name: '{{userName}}',
email: '{{userEmail}}'
})
}
}
});
// Serialize to JSON
console.log(serializeZap(collection, 2));
console.log(serializeZap(createUserRequest, 2));
import { mergeZapVariables, replaceVariables, extractVariables } from 'zap-lang';
// Complex variable merging with session state
const variables = mergeZapVariables({
global: { timeout: 5000, retries: 3 },
environment: { baseUrl: 'https://api.dev.example.com' },
collection: { version: 'v1' },
folder: { endpoint: '/users' },
request: { userId: '{{createdUserId}}' }, // Dynamic from previous request
sessionVars: {
token: 'session-token',
createdUserId: '12345' // From previous request response
}
});
// Template processing
const urlTemplate = '{{baseUrl}}/{{version}}{{endpoint}}/{{userId}}';
const resolvedUrl = replaceVariables(urlTemplate, variables);
console.log(resolvedUrl); // 'https://api.dev.example.com/v1/users/12345'
// Find missing variables
const requiredVars = extractVariables('{{baseUrl}}/{{version}}/{{missingVar}}');
const missingVars = requiredVars.filter(v => !(v in variables));
if (missingVars.length > 0) {
console.warn('Missing variables:', missingVars);
}
const graphqlRequest = createApiRequest({
meta: { name: 'Get User Profile' },
request: {
url: '{{graphqlEndpoint}}',
headers: [
{ name: 'Content-Type', value: 'application/json' },
{ name: 'Authorization', value: 'Bearer {{token}}' }
],
body: {
type: 'graphql',
content: `
query GetUser($userId: ID!) {
user(id: $userId) {
id
name
email
profile {
avatar
bio
}
}
}
`
}
},
variables: {
userId: '{{currentUserId}}'
}
});
// Convert to axios config
const axiosConfig = zapRequestToAxiosConfig(graphqlRequest, {
graphqlEndpoint: 'https://api.example.com/graphql',
token: 'your-token',
currentUserId: '123'
});
// The body will be properly formatted as:
// { query: "...", variables: { userId: "123" } }
The package automatically detects request types based on structure:
method
and url
fieldsurl
and body.type: 'graphql'
fieldsurl
and wsMessage
fieldsfileOp
fieldSupported body types in requests:
{ type: 'json', content: '...' }
- JSON content{ type: 'raw', content: '...' }
- Raw text content{ type: 'form', form: [{ name: '...', value: '...' }] }
- Form data{ type: 'urlencoded', urlencoded: [{ name: '...', value: '...' }] }
- URL-encoded form{ type: 'binary', file: '...' }
- Binary file{ type: 'none' }
- No body{ type: 'graphql', content: '...' }
- GraphQL query# Install dependencies
npm install
# Run tests
npm test
# Build for production
npm run build
# Build for Node.js environment
npm run build:node
# Development mode with watch
npm run dev
This package is built for browser environments and works in:
The package includes comprehensive tests covering:
MIT
FAQs
Zap Lang parser and validator - A human-friendly, JSON-based language for describing HTTP requests, collections, environments, and variables for API testing
The npm package zap-lang receives a total of 2 weekly downloads. As such, zap-lang popularity was classified as not popular.
We found that zap-lang demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer 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
npm now supports Trusted Publishing with OIDC, enabling secure package publishing directly from CI/CD workflows without relying on long-lived tokens.
Research
/Security News
A RubyGems malware campaign used 60 malicious packages posing as automation tools to steal credentials from social media and marketing tool users.
Security News
The CNA Scorecard ranks CVE issuers by data completeness, revealing major gaps in patch info and software identifiers across thousands of vulnerabilities.