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 🙏

© 2024 – Pkg Stats / Ryan Hefner

yea

v1.5.0

Published

Immutable-style AJAX library for the browser

Downloads

28

Readme

yea

Build Status NPM GitHub

Yea... an immutable-style AJAX library for the browser.

Requests are configured via method calls and each method always returns a fresh request instance, with no references to past instances.

Principles

Why not use fetch, axios, jQuery, etc..? See COMPARISON.md.

Contents

Installation

Via CDN

<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/yea.min.js"></script>
<script>
  yea.get('https://reqres.in/api/users').then(response => {
    console.log(response.status);
    console.log(response.body); // string (original JSON)
    console.log(response.data); // object
  });
</script>

View example in JSFiddle

Via npm

Install via npm or yarn:

npm install yea
# or
yarn add yea

Import in a project:

import request from 'yea';
// or
const request = require('yea');

Usage

See these basic examples or the full API below.

// Make a GET request
request
  .get('https://example.com')
  .query({ foo: 'bar' })
  .then(response => {
    console.log(response.body);
  })
  .catch(error => {
    console.error(error.response.status);
  })

// ... with URL parameters
request
  .get('https://example.com/api/accounts/:accountId/info')
  .urlParams({ accountId: 123 })

// Make a POST request
request
  .post('https://example.com/accounts')
  .body('raw data')

// Make a POST request (json)
request
  .post('https://example.com/accounts')
  .json({ foo: 'bar' })

// Make a POST request (urlencoded)
request
  .post('https://example.com/accounts')
  .urlencoded({ foo: 'bar' })

// Set a base URL
request
  .baseUrl('https://example.com')
  .get('/accounts')

// Set headers
request
  .get('https://example.com')
  .headers({
    'X-Random': 1
  })
  .header('x-another', 'test')
  .unsetHeader('x-another')

// Set a timeout
request
  .get('https://example.com')
  .timeout(2000)

// JSON responses decoded automatically based on Content-Type header (can be turned off)
request
  .get('https://example.com/accounts.json')
  .then(response => {
    console.log(response.data);
  })

// Bring your own Promise
request
  .polyfills({ Promise: require('bluebird') })
  .get('https://example.com')

// You can use async/await of course
const { status, body } = await request.get('http://example.com')

// Helper method to return a nested value from the request
const status = await request.get('https://example.com/accounts.json').prop('status')
const contentType = await request.get('https://example.com/accounts.json').prop(['headers', 'content-type'])
const data = await request.get('https://example.com/accounts.json').prop('data')
const account = await request.get('https://example.com/accounts.json').prop('data.accounts[0]')

Usage with TypeScript

Yea comes with built-in type declarations.

import yea, { YeaRequestError } from 'yea';
request.get('https://example.com').then(response => {
  // Response is implicitly an instance of YeaResponse
  console.log(response.body);
}).catch((error: YeaRequestError) => {
  console.error(error.response.status);
});

API

The following methods are available.

get

.get(url)

Where url is a string. Shorthand for request.method('get').url(url).

post

.post(url)

Where url is a string. Shorthand for request.method('post').url(url).

put

.put(url)

Where url is a string. Shorthand for request.method('put').url(url).

delete

.delete(url)

Where url is a string. Shorthand for request.method('delete').url(url).

method

Sets the HTTP method.

.method(method)

Where method is a string, e.g. 'get' or 'GET'.

url

Sets the full URL of the request. If a query-string is present, it will override any previously set query parameters.

.url(url)

Where url is a string, e.g. 'https://example.com/accounts'.

urlParams

Sets URL parameters which will be replaced from the URL when the request is sent.

.urlParams(object)

Where object is an object.

Example:

// Will make request to "/api/accounts/123/info"
request.get('/api/accounts/:accountId/info').urlParams({ accountId: 123 })

baseUrl

Sets the base URL to which all subsequent request URLs will be appended.

.baseUrl(url)

Where url is a string, e.g. 'https://example.com'.

A few examples of practical usage:

request.baseUrl('https://example.com').url('accounts')    // => https://example.com/accounts
request.baseUrl('https://example.com').url('/accounts')   // => https://example.com/accounts
request.baseUrl('https://example.com/nested').url('/accounts')     // => https://example.com/nested/accounts
request.baseUrl('https://example.com/nested/foo').url('accounts')  // => https://example.com/nested/foo/accounts

query

Sets query parameters from an object or a string. Overwrites existing query.

.query(object | string)

Where object is key-value object of query parameters to set, or a valid query string.

Example:

request.query({ first: 'foo', second: 'bar' })
request.query('first=foo&second=bar')

headers

Sets request headers from an object. Overwrites existing headers.

.headers(object)

Where object is key-value object of headers to set.

Example:

const req = request.headers({ 'x-example': 'foo' });
console.log(req.toObject().headers) // => { 'x-example': 'foo' }
// Overwrites all previous headers:
const req2 = req.headers({ 'x-token': 'secret123' });
console.log(req2.toObject().headers) // => { 'x-token': 'secret123' }

amendHeaders

Sets request headers from an object. Only overwrites headers present in the given object.

.amendHeaders(object)

Where object is key-value object of headers to set.

Example:

const req = request.headers({ 'x-example': 'foo' }).amendHeaders({ 'x-token': 'secret123' });
console.log(req.toObject().headers) // => { 'x-example': 'foo', 'x-token': 'secret123' }

header

Adds or updates a header value.

.header(key, value)

Where key is a string and value is a string.

Example:

const req = request.header('x-example', 'foo').header('x-token', 'secret123');
console.log(req.toObject().headers) // => { 'x-example': 'foo', 'x-token': 'secret123' }

unsetHeader

Removes a header from the request.

.unsetHeader(name)

Where name is a string.

Example:

const req = request.headers({ 'x-example': 'foo', 'x-token': 'secret123' }).unsetHeader('x-example');
console.log(req.toObject().headers) // => { 'x-token': 'secret123' }

body

Set the raw body of the request.

.body(data)

Where data is a string.

See also json and urlencoded.

json

Sets a JSON-encoded body and sets the Content-Type header to 'application/json'.

.json(value)

Where value is mixed.

Shorthand for request.header('Content-Type', 'application/json').body(JSON.stringify(value)).

urlencoded

Sets a URL-encoded body and sets the Content-Type header to 'application/urlencoded'.

.urlencoded(data)

Where value is an object.

Shorthand for request.header('content-type', 'application/x-www-form-urlencoded').body(_valueUrlEncoded_).

timeout

Sets a timeout after which the request will be aborted and the Promise rejected.

.timeout(milliseconds)

Where milliseconds is an integer.

See also unsetTimeout.

unsetTimeout

Removes the timeout-value previously set with timeout.

.unsetTimeout()

prop

Sets a path (similar to lodash.get) which will be resolved once the response is returned.

.prop(path)

Where path is a string or an array.

Example:

const account = await request.get('...').prop('data.accounts[0]');
const contentType = await request.get('...').prop(['headers', 'content-type']);

send

Dispatches the request and returns a Promise.

.send([body])

Where the optional argument body is a string. If it is set, it will be set as the request body. Also see sendJson and sendUrlencoded.

The Promise resolves with a response object.

request
  .get('https://example.com')
  .then(response => {
    console.log(response.headers); // object
    console.log(response.body); // string
    console.log(response.status); // integer
  })
  .catch(error => {
    console.log(error.message);
    console.log(error.response); // Similar structure as successful response
  })

A new Promise is always returned, and the YeaAjaxRequest is not mutated, so you can send the same request multiple times.

const req = request.get('https://example.com');
req.send().then(response => {
  console.log('first response', response);
});
req.send().then(() => {
  console.log('second response', response);
});

See polyfills for switching away from global Promise (e.g. bluebird).

Note that calling .send() is not always necessary. You can usually directly call .then().

sendUrlencoded

Shorthand for .urlencoded(data).send().

.sendUrlencoded(data)

sendJson

Shorthand for .json(data).send().

.sendJson(data)

setResponseTransformers

Sets a list of response transformers which are called when a response is received. By default the list contains one transformer which decodes JSON bodies based on the response Content-Type header.

Using this method you can remove the default transformer:

.setResponseTransformers([])

If you need to add it back, just set it again:

request.setResponseTransformers([ request.jsonResponseTransformer ]);

Transformer functions are executed sequentially in the order they are in the list, and they receive response as the only parameter. Whatever value they return is passed onto the next transformer and eventually back to the Promise-chain.

request.setResponseTransformers([
  response => {
    response.foobar = 'some extra information from elsewhere, for example';
    return response;
  }
]);

Reference to the original array is lost:

const array = [];
const req = request.setResponseTransformers(array);
array.push(someFunction);
req.toObject().responseTransformers; // not affected by the push, still []

setAllowedStatusCode

By default any 2XX status code resolves the Promise and other status codes will reject it. This can be customized using setAllowedStatusCode.

.setAllowedStatusCode(allowed)

Where allowed is an integer, a RegExp or a function.

polyfills

Override global dependencies which are used internally. Most useful for adding polyfills or a custom Promise-implementation.

.polyfills(polyfills)

Where polyfills is an object. See example for the possible dependencies you can override:

request.polyfills({
  Promise: window.Promise
})

Links to polyfills for older browsers if you need to support them (these can automatically patch window.Promise; no need to use request.polyfills):

then

Sends the request and resolves like a normal Promise.

.then(arguments)

Where arguments are what you would submit to a then-handler of a Promise.

The following examples are basically equivalent:

const responseHandler = response => { /* ... */ };

// using .then()
yea.get('http://example.com').then(responseHandler)

// using .send()
yea.get('http://example.com').send().then(responseHandler)

toObject

Returns the request configuration as an object.

.toObject()
.config() // alias
.debug() // alias

Example:

const req = request.baseUrl('http://example.com').get('/info').header('X-Random', 'foo')
const config = req.toObject(); // or req.config() or req.debug()
// =>
// {
//   method: 'GET',
//   url: 'http://example.com/info',
//   body: '',
//   headers: {
//     'x-random': 'foo'
//   },
//   allowedStatusCode: /^2[0-9]{2}$/,
//   timeout: null,
//   responseTransformers: [
//     req.jsonResponseTransformer
//   ],
// }

Inspect request config

Use the API methods toObject, config or debug to inspect the configuration of an YeaAjaxRequest instance.

const req = request.get('https://example.com');
console.log(req.toObject().url);

Extending (instances)

Each method of YeaAjaxRequest returns a new instance of YeaAjaxRequest. This is demonstrated in the example below.

The example uses toObject which returns a copy of all configuration of that specific instance at that moment in time.

const req1 = request
  .get('https://example.com')
  .query({ foo: 'bar' });

// Extend from previous request
const req2 = req1.query({ something: 'different' });

console.log(req2 === req1); // => false
console.log(req1.toObject().query); // => 'foo=bar'
console.log(req2.toObject().query); // => 'something=different'

Practical example of how to create a base request with some defaults and later utilize it for requests:

const api = request
  .baseUrl('https://example.com/api/v1')
  .headers({
    'X-API-KEY': 'secret123'
  });

// The following requests will use the base URL and headers set above
api.get('/accounts').send();
api.post('/accounts').body(data).send();

Development

Tests

For local development, run yarn dev. It starts a web server and watches for changes. You can view the tests in the browser at http://localhost:9876.

$ yarn dev
Test server is running!
Open http://localhost:9876/ in your browser

For a one-time full test suite execution, run yarn test. It runs all tests in a suite of browsers (powered by Karma).

yarn test

Browser support

Chrome, Firefox, IE 10+, Edge, Safari 11+

Cross-browser Testing Platform Provided by Sauce Labs.

Changelog

See CHANGELOG.md.

License

MIT