json-api 0.1.0.2 → 0.1.0.3
raw patch · 3 files changed
+136/−5 lines, 3 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Network.JSONApi.Document: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (Network.JSONApi.Document.ErrorDocument a b)
- Network.JSONApi.Document: instance (GHC.Classes.Eq a, GHC.Classes.Eq b, GHC.Classes.Eq c) => GHC.Classes.Eq (Network.JSONApi.Document.Document a b c)
- Network.JSONApi.Document: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Network.JSONApi.Document.ErrorDocument a b)
- Network.JSONApi.Document: instance (GHC.Show.Show a, GHC.Show.Show b, GHC.Show.Show c) => GHC.Show.Show (Network.JSONApi.Document.Document a b c)
- Network.JSONApi.ResourceObject: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (Network.JSONApi.ResourceObject.ResourceObject a b)
- Network.JSONApi.ResourceObject: instance (GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (Network.JSONApi.ResourceObject.ResourceObject a b)
- Network.JSONApi.ResourceObject: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Network.JSONApi.ResourceObject.ResourceObject a b)
+ Network.JSONApi.Document: instance (GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (Network.JSONApi.Document.ErrorDocument a b)
+ Network.JSONApi.Document: instance (GHC.Classes.Eq c, GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (Network.JSONApi.Document.Document a b c)
+ Network.JSONApi.Document: instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Network.JSONApi.Document.ErrorDocument a b)
+ Network.JSONApi.Document: instance (GHC.Show.Show c, GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Network.JSONApi.Document.Document a b c)
+ Network.JSONApi.ResourceObject: instance (GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (Network.JSONApi.ResourceObject.ResourceObject a b)
+ Network.JSONApi.ResourceObject: instance (GHC.Classes.Ord b, GHC.Classes.Ord a) => GHC.Classes.Ord (Network.JSONApi.ResourceObject.ResourceObject a b)
+ Network.JSONApi.ResourceObject: instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Network.JSONApi.ResourceObject.ResourceObject a b)
Files
- README.md +107/−1
- example/README.md +28/−3
- json-api.cabal +1/−1
README.md view
@@ -3,14 +3,120 @@ ## Haskell Implementation of the JSON-API specification ++#### Motivation++From the specification itself:++> If you’ve ever argued with your team about the way your JSON responses should+> be formatted, JSON API can be your anti-bikeshedding tool.+> +> By following shared conventions, you can increase productivity, take advantage+> of generalized tooling, and focus on what matters: your application.+> +> Clients built around JSON API are able to take advantage of its features around+> efficiently caching responses, sometimes eliminating network requests entirely.++All in all, API discoverability and other [HATEOAS](https://spring.io/understanding/HATEOAS)+principles make JSON-API an attractive resource serialization option.+++ #### The specification Find the specification [here](http://jsonapi.org/) + #### Example usage -There is an [example project](https://github.com/toddmohney/json-api/example) illustrating how the library can be used.+Let's start with an example User record:++```Haskell+data User = User+ { userId :: Int+ , userFirstName :: String+ , userLastName :: String+ } deriving (Eq, Show)++$(deriveJSON defaultOptions ''User)+```++From this, we can use the `json-api` package to produce a payload conformant+to the [JSON-API specification](http://jsonapi.org/) like so:++```Haskell+-- Builds the Document which will be serialized as our+-- web server's response payload+mkDocument :: User -> Links -> Document User Text Int+mkDocument usr links =+ Document+ (Singleton $ toResourceObject usr)+ (Just links)+ Nothing++-- Helper function to convert a User into a resource object+-- This could be our canonical serialization function for a User in any+-- response payload+toResourceObject :: User -> ResourceObject User Text+toResourceObject user =+ ResourceObject resourceId resourceType user resourceLinks resourceMetaData+ where+ resourceId = ResourceId . pack . show . userId $ user+ resourceType = ResourceType "User"+ resourceLinks = Just $ userLinks user+ resourceMetaData = Nothing++-- helper function to build links for a User resource+userLinks :: User -> Links+userLinks user = toLinks [ ("self", selfLink) ]+ where+ selfLink = toURL selfPath+ selfPath = "/users/" <> (show $ userId user)+```++When delivered as a response from a web server, for example, we get a payload+that looks like this:++```JSON+{+ "data":{+ "attributes":{+ "userFirstName":"Isaac",+ "userLastName":"Newton",+ "userId":1+ },+ "id":"1",+ "meta":null,+ "type":"User",+ "links":{+ "self":"/users/1"+ }+ },+ "meta":null,+ "links":{+ "self":"/users/1"+ }+}+```++Neat! We can see that if we would like the full User data for the User with+ID=1, we can query `/users/1`. Discoverability!++We can also see from the top-level `links` data that this particular payload originated+from `/users/1`.++This is a very simple example to provide an introduction to the basic idea+behind JSON-API and how to use this library. Check out [these examples](http://jsonapi.org/examples/)+for more robust representations of resourceful payloads. Here, you'll start to+see the more comprehensive benefits of a discoverable API.++++#### Example Project++There is an [example project](https://github.com/toddmohney/json-api/tree/master/example) illustrating how the library can be used in the context of a web server.+ #### Hackage
example/README.md view
@@ -1,8 +1,33 @@ +#### Running the example +There's a `stack.yaml` file in this directory, so you can run and build this+example project in a familiar manner.++```bash+# pull your GHC deps+stack setup++# build the project+stack build++# run the webserver+stack exec example-exe+```++At this point you should have a webserver running at `http://localhost:8080`+You'll find available endpoints at the following urls:+- [http://localhost:8080/users](http://localhost:8080/users) - responds with a list of User resources+- [http://localhost:8080/users/1](http://localhost:8080/users/1) - responds with a singleton resource+- [http://localhost:8080/users/2](http://localhost:8080/users/2) - responds with a singleton resource+- [http://localhost:8080/users/3](http://localhost:8080/users/3) - responds with a 404 and error payload++++ ## List Resource Example -```json+```JSON GET /users {@@ -46,7 +71,7 @@ ## Singleton Resource Example -```json+```JSON GET /users/1 {@@ -73,7 +98,7 @@ ## Error Example -```json+```JSON GET /users/3 {
json-api.cabal view
@@ -1,5 +1,5 @@ name: json-api-version: 0.1.0.2+version: 0.1.0.3 homepage: https://github.com/toddmohney/json-api bug-reports: https://github.com/toddmohney/json-api/issues license: MIT