Skip to content

Commit

Permalink
feat: Allow adding multiple query params with the same key.
Browse files Browse the repository at this point in the history
On the backs of 2cb963e, this commit documents
the methods to use to `append` new query params without overwriting
the existing values with the same key.

BREAKING CHANGE: The `getQueryParams` and `setQueryParams` methods have
changed to represent the new internal structure of query params in Hyper.
These now are represented internally as an array of structs to support
duplicate keys in query strings.  You _probably_ want the
`getQueryParamByName` and `getAllQueryParamsByName` instead of
`getQueryParams` and `withQueryParams` or `appendQueryParams` methods
instead of `setQueryParams`. One more item of note, the `getQueryParam`\
method has been deprecated in favor of `getQueryParamByName`.
  • Loading branch information
elpete committed Jul 29, 2022
1 parent b422012 commit 166a61b
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 10 deletions.
71 changes: 68 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ Hyper runs on Adobe ColdFusion 11+ and Lucee 5+.

ColdBox is not required, but mappings are provided for ColdBox users automatically.

### Upgrade from v3

The only changes between v3 and v4 is with the `getQueryParams` and `setQueryParams` methods.
These now are represented internally as an array of structs to support duplicate keys in
query strings. You _probably_ want the `getQueryParamByName` and `getAllQueryParamsByName`
instead of `getQueryParams` and `withQueryParams` or `appendQueryParams` methods
instead of `setQueryParams`.

One more item of note, the `getQueryParam` method has been deprecated in favor of `getQueryParamByName`.

### HyperBuilder

The component you will most likely inject is the `HyperBuilder`. This is
Expand Down Expand Up @@ -522,6 +532,9 @@ A convenience method to set the Accept header.

Gets the query parameters for the request.

**This method returns an array of param structs that is used under the hood by Hyper.**
**You probably want to use `getQueryParamByName` or `getAllQueryParamsByName` instead.**

| Name | Type | Required | Default | Description |
| ------------ | ---- | -------- | ------- | ----------- |
| No arguments | | | | |
Expand All @@ -530,13 +543,56 @@ Gets the query parameters for the request.

Sets the query parameters for the request.

| Name | Type | Required | Default | Description |
| ----- | ------ | -------- | ------- | ------------------------------------- |
| value | struct | true | | The query parameters for the request. |
**This method accepts an array of param structs that is used under the hood by Hyper.**
**You probably want to use `withQueryParams` or `appendQueryParams` instead.**

If needed, param structs have two keys, `name` and `value`.

| Name | Type | Required | Default | Description |
| ----- | ------ | -------- | ------- | ---------------------------------------------------------- |
| value | array | true | | The query parameters for the as an array of param structs. |

##### `getQueryParam`

**DEPRECATED:** Use `getQueryParamByName`
Gets the first value for a certian query parameter.
Returns an empty string if the query parameter does not exist.

| Name | Type | Required | Default | Description |
| ---- | ------ | -------- | ------- | -------------------------------------------------------------|
| name | string | true | | The name of the query parameter to retrieve the first value. |

##### `getQueryParamByName`

Gets the first value for a certian query parameter.
Returns an empty string if the query parameter does not exist.

| Name | Type | Required | Default | Description |
| ---- | ------ | -------- | ------- | -------------------------------------------------------------|
| name | string | true | | The name of the query parameter to retrieve the first value. |

##### `getAllQueryParamsByName`

Get all the values for a certian query parameter.
Returns an empty array if the query parameter does not exist.

| Name | Type | Required | Default | Description |
| ---- | ------ | -------- | ------- | -------------------------------------------------------------- |
| name | string | true | | The name of the query parameter to retrieve all of its values. |

##### `setQueryParam`

Set a query parameter for the request.
Note: This removes all other query params with the same name.

| Name | Type | Required | Default | Description |
| ----- | ------ | -------- | ------- | --------------------------------- |
| name | string | true | | The name of the query parameter. |
| value | string | true | | The value of the query parameter. |

##### `appendQueryParam`

Append a query parameter for the request.

| Name | Type | Required | Default | Description |
| ----- | ------ | -------- | ------- | --------------------------------- |
Expand All @@ -546,6 +602,15 @@ Set a query parameter for the request.
##### `withQueryParams`

Add additional query parameters to the request.
Note: This will remove any values with duplicate keys prior to adding the new struct of params.

| Name | Type | Required | Default | Description |
| ----------- | ------ | -------- | ------- | --------------------------------------------------- |
| queryParams | struct | true | | A struct of query parameters to add to the request. |

##### `appendQueryParams`

Appends additional query parameters to the request.

| Name | Type | Required | Default | Description |
| ----------- | ------ | -------- | ------- | --------------------------------------------------- |
Expand Down
45 changes: 38 additions & 7 deletions models/HyperRequest.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,9 @@ component accessors="true" {

/**
* Add additional query parameters to the request.
* Note: This will remove any values with duplicate keys prior to adding the new struct of params.
*
* @queryParams A struct of query parameters to add to the request.
* @queryParams A struct of query parameters to set for the request.
*
* @returns The HyperRequest instance.
*/
Expand All @@ -398,9 +399,23 @@ component accessors="true" {
return this;
}

/**
* Appends additional query parameters to the request.
*
* @queryParams A struct of query parameters to append to the request.
*
* @returns The HyperRequest instance.
*/
function appendQueryParams( queryParams = {} ) {
for ( var name in arguments.queryParams ) {
appendQueryParam( name, arguments.queryParams[ name ] );
}
return this;
}

/**
* Set a query parameter for the request.
* This will delete any existing query params for the key first.
* Note: This removes all other query params with the same name.
*
* @name The name of the query parameter.
* @value The value of the query parameter.
Expand All @@ -427,7 +442,10 @@ component accessors="true" {
* @returns The HyperRequest instance.
*/
function appendQueryParam( name, value ) {
variables.queryParams.append( { "name": arguments.name, "value": arguments.value } );
variables.queryParams.append( {
"name" : arguments.name,
"value" : arguments.value
} );
return this;
}

Expand All @@ -449,14 +467,27 @@ component accessors="true" {
}

/**
* Get the first value for a certian query parameter.
* Gets the first value for a certian query parameter.
* @deprecated Use `getQueryParamByName`
*
* @name The name of the query parameter to retrieve its value.
*
* @returns The value of the query parameter.
* @returns The value of the query parameter to retrieve the first value.
* Returns an empty string if the query parameter does not exist.
*/
function getQueryParam( name ) {
return getQueryParamByName( arguments.name );
}

/**
* Gets the first value for a certian query parameter.
*
* @name The name of the query parameter to retrieve its value.
*
* @returns The value of the query parameter to retrieve the first value.
* Returns an empty string if the query parameter does not exist.
*/
function getQueryParamByName( name ) {
for ( var i = 1; i <= variables.queryParams.len(); i++ ) {
var param = variables.queryParams[ i ];
if ( param.name == arguments.name ) {
Expand All @@ -469,12 +500,12 @@ component accessors="true" {
/**
* Get all the values for a certian query parameter.
*
* @name The name of the query parameter to retrieve its value.
* @name The name of the query parameter to retrieve all of its values.
*
* @returns An array of values for the query parameter.
* Returns an empty array if the query parameter does not exist.
*/
function getAllQueryParam( name ) {
function getAllQueryParamsByName( name ) {
return variables.queryParams.filter( function( param ) {
return param.name == name;
} );
Expand Down
24 changes: 24 additions & 0 deletions tests/specs/integration/GetSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,30 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
);
} );

it( "can add additional query params with the same name", function() {
var res = hyper
.setBaseUrl( "https://jsonplaceholder.typicode.com" )
.setUrl( "/posts" )
.appendQueryParam( "foo", "bar" )
.appendQueryParam( "foo", "baz" )
.get();
expect( res.getRequest().getFullUrl( withQueryString = true ) ).toBeWithCase(
"https://jsonplaceholder.typicode.com/posts?foo=bar&foo=baz"
);
} );

it( "can append multiple query params at once", function() {
var res = hyper
.setBaseUrl( "https://jsonplaceholder.typicode.com" )
.setUrl( "/posts" )
.appendQueryParams( { "foo" : "bar" } )
.appendQueryParams( { "foo" : "baz", "one" : "two" } )
.get();
expect( res.getRequest().getFullUrl( withQueryString = true ) ).toBeWithCase(
"https://jsonplaceholder.typicode.com/posts?foo=bar&foo=baz&one=two"
);
} );

it( "has access to the original HyperRequest in the HyperResponse", function() {
var res = hyper.get( "https://jsonplaceholder.typicode.com/posts/1" );
expect( res ).toBeInstanceOf( "HyperResponse", "A HyperResponse object should have been returned." );
Expand Down

0 comments on commit 166a61b

Please sign in to comment.