Skip to content

Commit

Permalink
Merge pull request #8 from okgrow/0.4.0
Browse files Browse the repository at this point in the history
0.4.0
  • Loading branch information
ccuilla committed Apr 27, 2018
2 parents 51dd7b5 + 340cfe6 commit c2aae41
Show file tree
Hide file tree
Showing 15 changed files with 853 additions and 97 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [0.4.0] - 2018-04-27

### Added

* `RegularExpression` scalar type _generator_
* `UnsignedInt` alias for `NonNegativeInt`
* `UnsignedFloat` alias for `NonNegativeFloat`

## [0.3.0] - 2018-04-06

### Changed
Expand Down
181 changes: 140 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,68 @@
> A library of custom GraphQL [scalar types](http://graphql.org/learn/schema/#scalar-types) for creating precise type-safe GraphQL schemas.
## Installation

```
npm install --save @okgrow/graphql-scalars
```

or

```
yarn add @okgrow/graphql-scalars
```

## Usage

To use these scalars you'll need to add them in two places, your schema and your resolvers map.

NOTE: The new `RegularExpression` scalar will be used a little differently and is explained below.

In your schema:

```graphql
scalar DateTime

scalar NonPositiveInt

scalar PositiveInt

scalar NonNegativeInt

scalar NegativeInt

scalar NonPositiveFloat

scalar PositiveFloat

scalar NonNegativeFloat

scalar NegativeFloat

scalar EmailAddress

scalar URL

scalar PhoneNumber

scalar PostalCode
```

In your resolver map, first import them:

```js
import {
DateTime,

NonPositiveInt,
PositiveInt,
NonNegativeInt,
NegativeInt,

NonPositiveFloat,
PositiveFloat,
NonNegativeFloat,
NegativeFloat,

EmailAddress,
URL,

PhoneNumber,
PostalCode,
} from '@okgrow/graphql-scalars';
Expand Down Expand Up @@ -87,10 +102,14 @@ const myResolverMap = {
Mutation: {
// more stuff here
},
}
};
```

NOTE: `NonNegativeFloat` and `NonNegativeInt` are also available under the aliases `UnsignedFloat`
and `UnsignedInt`, respectively.

Alternatively, use the default import and ES6's spread operator syntax:

```js
import OKGGraphQLScalars from '@okgrow/graphql-scalars';
```
Expand All @@ -108,11 +127,11 @@ const myResolverMap = {
Mutation: {
// more stuff here
},
}
};
```


That's it. Now you can use these scalar types in your schema definition like this:

```graphql
type Person {
birthDate: DateTime
Expand All @@ -130,70 +149,145 @@ type Person {
phoneNumber: PhoneNumber
homePostalCode: PostalCode
}

```

These scalars can be used just like the base, built-in ones.

### Using the RegulareExpression scalar

First an explanation: To create a new scalar type to the GraphQL schema language, you must create an
instance of a new `GraphQLScalarType` object that implements three general functions/methods:
`serialize`, `parseValue` and `parseLiteral` which are used at different stages of processing your
GraphQL types during queries and mutations. So creating a new scalar looks like this:

```
const MyScalar = new GraphQLScalarType({
'MyScalar',
description: 'A description of my scalar',
serialize(value) {
// ...
return value;
},
parseValue(value) {
// ...
return value;
},
parseLiteral(ast) {
// ...
return ast.value;
}
});
```

Given this, if we want to create a new type that is essentially the same except for one little
customizable aspect (e.g., a regular expression type that has all the same code except the regex is
different) then we need to dynamically _generate_ a new `GraphQLScalarType` object given some
parameters. That's the approach we take here.

Therefore the `RegularExpression` scalar type is really a `GraphQLScalarType` object _generator_
that takes two arguments:

* a name
* the regex you want it to use

So to create a new scalar for a given regex, you will do this:

```
const MyRegexType = new RegexType('MyRegexType', /^ABC$/);
```

Now `MyRegexType` is your new GraphQL scalar type that will enforce a value of, in this case, "ABC".

Add your new scalar type to your esolver map:

```
export default {
MyRegexType,
};
```

And to your schema:

```
scalar MyRegexType
```

That's it. Now you can use `MyRegexType` as a type in the rest of your schema.

## Why?

The primary purposes these scalars, really of _all_ types are to:

1. Communicate to users of your schema exactly what they can expect or to at least _reduce_
ambiguity in cases where that's possible. For example if you have a `Person` type in your schema
and that type has as field like `ageInYears`, the value of that can only be null or a positive
integer (or float, depending on how you want your schema to work). It should never be zero or
negative.
1. Run-time type checking. GraphQL helps to tighten up the contract between client and server. It
does this with strong typing of the _interface_ (or _schema_). This helps us have greater
confidence about what we're receiving from the server and what the server is receiving from the
client.
1. Communicate to users of your schema exactly what they can expect or to at least _reduce_
ambiguity in cases where that's possible. For example if you have a `Person` type in your schema
and that type has as field like `ageInYears`, the value of that can only be null or a positive
integer (or float, depending on how you want your schema to work). It should never be zero or
negative.
1. Run-time type checking. GraphQL helps to tighten up the contract between client and server. It
does this with strong typing of the _interface_ (or _schema_). This helps us have greater
confidence about what we're receiving from the server and what the server is receiving from the
client.

This package adds to the base options available in GraphQL to support types that are reasonably
common in defining schemas or interfaces to data.


## The Types

### DateTime

Use real JavaScript Dates for GraphQL fields. Currently you can use a String or an Int (e.g., a
timestamp in milliseconds) to represent a date/time. This scalar makes it easy to be explicit about
the type and have a real JavaScript Date returned that the client can use _without_ doing the
inevitable parsing or conversion themselves.

### NonNegativeInt

Integers that will have a value of 0 or more. Uses [`parseInt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt).

### NonPositiveInt

Integers that will have a value of 0 or less. Uses [`parseInt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt).

### PositiveInt

Integers that will have a value greater than 0. Uses [`parseInt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt).

### NegativeInt

Integers that will have a value less than 0. Uses [`parseInt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt).

### NonNegativeFloat

Floats that will have a value of 0 or more. Uses [`parseFloat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat).

### NonPositiveFloat

Floats that will have a value of 0 or less. Uses [`parseFloat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat).

### PositiveFloat

Floats that will have a value greater than 0. Uses [`parseFloat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat).

### NegativeFloat

Floats that will have a value less than 0. Uses [`parseFloat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat).

### EmailAddress

A field whose value conforms to the standard internet email address format as specified in
[RFC822](https://www.w3.org/Protocols/rfc822/).

### URL

A field whose value conforms to the standard URL format as specified in
[RFC3986](https://www.ietf.org/rfc/rfc3986.txt).

### PhoneNumber

A field whose value conforms to the standard E.164 format as specified in
[E.164 specification](https://en.wikipedia.org/wiki/E.164). Basically this is `+17895551234`.
The very powerful
Expand All @@ -202,38 +296,43 @@ _that_ format, parse and display it in whatever display format you want. It can
parse user input and _get_ the E.164 format to pass _into_ a schema.

### PostalCode
We're going to start with a limited set as suggested [here] (http://www.pixelenvision.com/1708/zip-postal-code-validation-regex-php-code-for-12-countries/)
and [here] (https://stackoverflow.com/questions/578406/what-is-the-ultimate-postal-code-and-zip-regex).

We're going to start with a limited set as suggested [here](http://www.pixelenvision.com/1708/zip-postal-code-validation-regex-php-code-for-12-countries/)
and [here](https://stackoverflow.com/questions/578406/what-is-the-ultimate-postal-code-and-zip-regex).

Which gives us the following countries:

- US - United States
- UK - United Kingdom
- DE - Germany
- CA - Canada
- FR - France
- IT - Italy
- AU - Australia
- NL - Netherlands
- ES - Spain
- DK - Denmark
- SE - Sweden
- BE - Belgium
- IN - India
* US - United States
* UK - United Kingdom
* DE - Germany
* CA - Canada
* FR - France
* IT - Italy
* AU - Australia
* NL - Netherlands
* ES - Spain
* DK - Denmark
* SE - Sweden
* BE - Belgium
* IN - India

This is really a practical decision of weight (of the package) vs. completeness.

In the future we might expand this list and use the more comprehensive list found [here] (http://unicode.org/cldr/trac/browser/tags/release-26-0-1/common/supplemental/postalCodeData.xml).
In the future we might expand this list and use the more comprehensive list found [here](http://unicode.org/cldr/trac/browser/tags/release-26-0-1/common/supplemental/postalCodeData.xml).

### RegularExpression

## Future
We'd like to keep growing this package, within reason, to include the scalar types that are widely
required when defining GraphQL schemas. We welcome both suggestions and pull requests. One idea
we're considering is:
A `GraphQLScalarType` object generator that takes two arguments:

- BLOB, could be could be a base64-encoded object of some kind
* `name` - The name of your custom type
* `regex` - The regex to be used to check against any values for fields with this new type

```
const MyRegexType = new RegexType('MyRegexType', /^ABC$/);
```

## What's this all about?

GraphQL is a wonderful new approach to application data and API layers that's gaining momentum. If
you have not heard of it, start [here](http://graphql.org/learn/) and check out
[Apollo](http://dev.apollodata.com/) also.
Expand All @@ -249,12 +348,12 @@ what this package does.
clean. Arguably not every project needs these additional scalar types. But _we_ have, and now _you_
can use them too if needed.


## License
Released under the [MIT license](https://github.com/okgrow/analytics/blob/master/License.md).

Released under the [MIT license](https://github.com/okgrow/analytics/blob/master/License.md).

## Contributing

Issues and Pull Requests are always welcome.

Please read our [contribution guidelines](https://okgrow.github.io/guides/docs/open-source-contributing.html).
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@okgrow/graphql-scalars",
"version": "0.3.0",
"version": "0.4.0",
"description": "A collection of scalar types not included in base GraphQL.",
"repository": {
"type": "git",
Expand Down

0 comments on commit c2aae41

Please sign in to comment.