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

rest-my-case

v1.0.33

Published

An http request helper for converting between cases

Downloads

147

Readme

RestMyCase

npm package

Rest my case is a tool for making networks requests between two systems with different variable cases written in typesript but can be used in any javascript environment. With rest my case you can decouple your api from the type system of its consumers, or make an external api fit the convention of your client.

An example of this might be that you have a javascript frontend (hopefully using camelCase) and python or ruby backend (using snake_case). However, you're not sure if you should convert your keys to camelCase for your web API. Rest My Case solves this by converting the keys of the outgoing request to the server case and upon receiving the incoming request, it converts the server cased keys back into the client case.

By default the client case is camelCase and the server case is snake_case. You can change the client and server case to your hearts desire and even write your own case conversion function (though this might be a little risky).

How it works

alt text

Installation

$ npm install rest-my-case

Creating a client

// client.ts
import Rmc, { HttpConfig, RmcClient } from 'rest-my-case';

let config = new HttpConfig();
//not necessary if you're hosting this from your website
config.hostname = 'www.mywebsite.com';
 //not necessary if you're hosting this from a site with the port set
config.port = 3000;
// not necessary if you want the protocol to be inferred from the webaddress
config.useHttps();
//also not necessary but all requests will be prefixed with this sub route
config.uriPrefix = 'api/v1';

let client: RmcClient = Rmc(config);
// OR if you have no need for a config
// let client: RmcClient = Rmc();

export default client;

How we might make requests with that client

import client from './client';

interface SuccessfulResponse {
  keyNumberOne: string,
  keyNumberTwo: number 
}

/* 
Note that the server will receive
{
  some_data: 123
}
and the server response will be 
{
  key_number_one: string,
  key_number_two: number
}
*/

async function requestExamples() {
    const getResponse = await client.get<SuccessfulResponse>('abc');
    const postResponse = await client.post<SuccessfulResponse>('abc', { someData: 123 });
    const putResponse = await client.put<SuccessfulResponse>('abc', { someData: 123 });
    const patchResponse = await client.patch<SuccessfulResponse>('abc', { someData: 123 });
    const deleteResponse = await client.delete<SuccessfulResponse>('abc', { someData: 123 });
}

Adding a query string

import client from './client';


async function queryExamples() {
    // this will make the api request /abc?my_data=foo&other_data=bar
    // you can also define the query string yourself you like by passing in a string
    const getSerializedQueryResponse = await client.get<SuccessfulResponse>('abc', {myData: 'foo', otherData: 'bar'});
    // this will make the api request /abc?foo=1&bar=2
    const getStringQueryResponse = await client.get<SuccessfulResponse>('abc', '?foo=1&bar=2');

    // for other types of requests that are not GET requests you can add a query with the query method
    // before invoking the network request method
    
    // this will post {my_data: 'foo', other_data: 'bar' } to /abc?page_index=10
    const postWithQueryResponse = await client.query({pageIndex: 10}).post('abc', { myData: 'foo', otherData: 'bar'});
    
    // Note you can of course pass in a raw string to the query method as well
}

Adding custom headers

You can override the headers by calling the headers method prior to the request

import client from './client';

/*
The default headers of HttpConfig are
  public headers: Headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  };
*/
async function headerExamples() {
    const getSerializedQueryResponse = await client
                                             .headers({'Content-Type': 'application/x-www-form-urlencoded'})
                                             .get<SuccessfulResponse>('abc');
}

Adding a request hook

A request hook can be added to the Http object if it is only used once. However, if you want your client to run a request hook with each request you must set it in the HttpConfig.

// client.ts
import Rmc, { HttpConfig, RmcClient, Http, Headers } from 'rest-my-case';

let config = new HttpConfig();

// This request hook ensures that if an authorization token exists in localstorage it will be set in the request's headers
config.requestHook = (http: Http, headers: Headers, data) : Http => {
  let authorizationToken = localStorage.get('token');
  if (authorizationToken !== undefined) {
    return http.headers({...headers, 'Authorization': authorizationToken});
  }
  return http;
}

let client: RmcClient = Rmc(config);
export default client;

Writing your own case conversion function

While you most likely want to use a tried and tested case conversion function, you may need to write your own. RestMyCase utilizes the change-case npm package to manage case conversions. If you want to write your own, the signature of a case conversion function is (str: string) => string. An example of this may be if your organization has a convention about keeping id in caps in camel case. For example user id is written userID, not userId. In that case you might want to write your own case conversion function.

import Rmc, { HttpConfig, RmcClient } from 'rest-my-case';
import { noCase } from 'change-case';

const camelCaseWithUpperCaseID = (str) => {
  return noCase(str)
    .toLowerCase()
    .split(' ')
    .map(s => s == 'id' ? 'ID': s)
    .map((s, i) => {
      if (i == 0) {
        return s;
      }
      var firstChar = s[0].toUpperCase();
      return firstChar + s.substr(1);
    })
    .join('');
}

let config = new HttpConfig();
// you could do the same thing for converting into the server case
config.clientCase = camelCaseWithUpperCaseID;
let client: RmcClient = Rmc(config);
export default client;

API

RmcClient

| Method/Property | Type | Description | | --- | --- | --- | | config | HttpConfig | The configuration object used for defining an RmcClient | | headers | (headers: Headers) => Http | A method that allows you to overrride the headers when building a custom rmc request | | uriPrefix | (uriPrefix: string) => Http | A method that allows you to overrride the urlPrefix when building a custom rmc request (e.g. /api/) | | requestHook | (responseHook: RequestHook) => Http | A method that allows you to overrride the request hook function for a custom rmc request | | responseHook | (responseHook: ResponseHook) => Http | A method that allows you to overrride the response hook function for a custom rmc request. You may want to invoke this if you needed to check the response data before it is serialzed into client case by rmc. | | query | (query: object|string) => Http | A method that allows you to add a query when building a rmc request. If you pass in an object the keys will be serialized in your server case. If you add a string, the query will not be serialized into server case. T denotes the type of the successful response that is resolved if used in typescript. | | get<T> | (uri: string, query?: string | {}) => ResponseType<T> | A regular get request. The first argument is the uri path (excluding the uriPrefix if set). The second optional argument is a query string or object, which will if an object the keys will be serialized in your server case. If the query parameter is a string, the query parameters will not be serialized into server case. T denotes the type of the successful response that is resolved if used in typescript. | | post<T> | (uri: string, param: {}) => ResponseType<T> | A regular post request. The first argument is the uri path (excluding the uriPrefix if set). The second argument is the data to be serialzed in the request. T denotes the type of the successful response that is resolved if used in typescript. | | put<T> | (uri: string, query?: param: {}) => ResponseType<T> | A regular put request. The first argument is the uri path (excluding the uriPrefix if set). The second argument is the data to be serialzed in the request. T denotes the type of the successful response that is resolved if used in typescript. | | patch<T> | (uri: string, param: {}) => ResponseType<T> | A regular patch request. The first argument is the uri path (excluding the uriPrefix if set). The second argument is the data to be serialzed in the request. T denotes the type of the successful response that is resolved if used in typescript. | | delete<T> | (uri: string, param: {}) => ResponseType<T> | A regular delete request. The first argument is the uri path (excluding the uriPrefix if set). The second argument is the data to be serialzed in the request. T denotes the type of the successful response that is resolved if used in typescript. | | options<T> | (uri: string, param: {}) => ResponseType<T> | An options request. The first argument is the uri path (excluding the uriPrefix if set). The second argument is the data to be serialzed in the request. T denotes the type of the successful response that is resolved if used in typescript. Note: Untested, use at your own discretion! | | head<T> | (uri: string, param: {}) => ResponseType<T> | A head request. The first argument is the uri path (excluding the uriPrefix if set). The second argument is the data to be serialzed in the request. T denotes the type of the successful response that is resolved if used in typescript. Note: Untested, use at your own discretion! | | trace<T> | (uri: string, param: {}) => ResponseType<T> | A trace request. The first argument is the uri path (excluding the uriPrefix if set). The second argument is the data to be serialzed in the request. T denotes the type of the successful response that is resolved if used in typescript. Note: Untested, use at your own discretion! | | connect<T> | (uri: string, param: {}) => ResponseType<T> | A connect request. The first argument is the uri path (excluding the uriPrefix if set). The second argument is the data to be serialzed in the request. T denotes the type of the successful response that is resolved if used in typescript. Note: Untested, use at your own discretion! | | request<T> | (method: HttpMethod, uri: string, param?: {}) => ResponseType<T> | A raw request method. You should not need to use this but if you prefer manually inserting the http method instead of using one of the rest methods provided to the RmcClient this is the method to call. T denotes the type of the successful response that is resolved if used in typescript.| | convertToServerCase | (data: any) => any | The method used to serialize data into the server case. Perhaps RMC doesn't support a given protocol such as WebSockets and you still want to take advantage of the ability to serialize client data into the server case, you can then manually use this method. | | convertToClientCase | (data: any) => any | The method used to serialize data into the client case. Perhaps RMC doesn't support a given protocol such as WebSockets and you still want to take advantage of the ability to serialize incoming server data into the client case, you can then manually use this method. |