Skip to content

Commit

Permalink
Merge pull request #63 from AlchemyCMS/add-deserializer
Browse files Browse the repository at this point in the history
Add deserializer JS files
  • Loading branch information
tvdeyen authored Sep 7, 2022
2 parents 95388c6 + d01f143 commit c7d31a2
Show file tree
Hide file tree
Showing 18 changed files with 865 additions and 72 deletions.
99 changes: 58 additions & 41 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: Ruby
name: Test

on:
- push
- pull_request

jobs:
build:
RSpec:
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -15,42 +15,59 @@ jobs:
env:
ALCHEMY_BRANCH: ${{ matrix.alchemy_branch }}
steps:
- uses: actions/checkout@v1
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.x
- name: Restore apt cache
id: apt-cache
uses: actions/cache@v1
with:
path: /home/runner/apt/cache
key: apt-sqlite-
- name: Install SQLite headers
run: |
sudo mkdir -p /home/runner/apt/cache
sudo apt-get update -qq
sudo apt-get install -qq --fix-missing libsqlite3-dev -o dir::cache::archives="/home/runner/apt/cache"
sudo chown -R runner /home/runner/apt/cache
- name: Install bundler
run: |
gem install bundler
- name: Restore Ruby Gems cache
id: cache
uses: actions/cache@v1
with:
path: vendor/bundle
key: bundle-${{ hashFiles('**/Gemfile.lock') }}-${{ matrix.alchemy_branch }}
restore-keys: |
bundle-
- name: Install bundle
timeout-minutes: 10
run: |
bundle install --jobs 4 --retry 3 --path vendor/bundle
- name: Build and test with RSpec
env:
RAILS_ENV: test
DB_USER: user
DB_PASSWORD: password
DB_PORT: ${{ job.services.mariadb.ports[3306] }}
run: bundle exec rake
- uses: actions/checkout@v1
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.x
- name: Restore apt cache
id: apt-cache
uses: actions/cache@v1
with:
path: /home/runner/apt/cache
key: apt-sqlite-
- name: Install SQLite headers
run: |
sudo mkdir -p /home/runner/apt/cache
sudo apt-get update -qq
sudo apt-get install -qq --fix-missing libsqlite3-dev -o dir::cache::archives="/home/runner/apt/cache"
sudo chown -R runner /home/runner/apt/cache
- name: Install bundler
run: |
gem install bundler
- name: Restore Ruby Gems cache
id: cache
uses: actions/cache@v1
with:
path: vendor/bundle
key: bundle-${{ hashFiles('**/Gemfile.lock') }}-${{ matrix.alchemy_branch }}
restore-keys: |
bundle-
- name: Install bundle
timeout-minutes: 10
run: |
bundle install --jobs 4 --retry 3 --path vendor/bundle
- name: Build and test with RSpec
env:
RAILS_ENV: test
DB_USER: user
DB_PASSWORD: password
DB_PORT: ${{ job.services.mariadb.ports[3306] }}
run: bundle exec rake
Jest:
runs-on: ubuntu-latest
env:
NODE_ENV: test
steps:
- uses: actions/[email protected]
- name: Restore node modules cache
uses: actions/[email protected]
with:
path: node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('./package.json') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install yarn
run: yarn install
- name: Run jest
run: yarn jest
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ spec/dummy/public
Gemfile.lock
.ruby-version
.idea
node_modules
yarn.lock
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"semi": false,
"trailingComma": "none",
"arrowParens": "always"
}
11 changes: 11 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Copyright 2020 Martin Meyerhoff, Thomas von Deyen

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20 changes: 0 additions & 20 deletions MIT-LICENSE

This file was deleted.

46 changes: 38 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,10 @@

A JSON-API based API for AlchemyCMS

## Usage
## Installation

Mount the engine in your `config/routes.rb` file where you want, like this:
### In your Alchemy Rails project

```rb
mount Alchemy::JsonApi::Engine => "/jsonapi/"
```

## Installation
Add this line to your application's Gemfile:

```ruby
Expand All @@ -27,8 +22,43 @@ Or install it yourself as:
$ gem install alchemy-json_api
```

### In your JS/Frontend app

Run this in your application:

```
yarn add "@alchemy_cms/json_api"
```

## Usage

### In your Rails app

Mount the engine in your Alchemy Rails app like this:

```rb
# config/routes.rb
mount Alchemy::JsonApi::Engine => "/jsonapi/"
```

> __NOTE__ Pick any path you like. This will be the **prefix** of your API URLs
### In your frontend app

This repo provides an NPM package with deserializers to help you convert the response into JS objects.

```js
import { deserializePages } from "@alchemy_cms/json_api"

const response = await fetch("/jsonapi/pages.json")
const data = await response.json()
const pages = deserializePages(data)

console.log(pages[0].name) // => Homepage
```

## Contributing
Contribution directions go here.

## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
The gem is available as open source under the terms of the [BSD-3-Clause license](https://opensource.org/licenses/BSD-3-Clause).
6 changes: 3 additions & 3 deletions alchemy-json_api.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ require "alchemy/json_api/version"
Gem::Specification.new do |spec|
spec.name = "alchemy-json_api"
spec.version = Alchemy::JsonApi::VERSION
spec.authors = ["Martin Meyerhoff"]
spec.authors = ["Martin Meyerhoff", "Thomas von Deyen"]
spec.email = ["[email protected]"]
spec.homepage = "https://github.com/AlchemyCMS/alchemy-json_api"
spec.summary = "A JSONAPI compliant API for AlchemyCMS"
spec.description = "A JSONAPI compliant API for AlchemyCMS"
spec.license = "MIT"
spec.license = "BSD-3-Clause"

spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
spec.files = Dir["{app,config,db,lib}/**/*", "LICENSE", "Rakefile", "README.md"]

spec.add_dependency "alchemy_cms", [">= 6.0.a", "< 6.1"]
spec.add_dependency "jsonapi.rb", "~> 1.6"
Expand Down
12 changes: 12 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
node: "current"
}
}
]
]
}
125 changes: 125 additions & 0 deletions dist/alchemy-json_api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var structuredClone = require('@ungap/structured-clone');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var structuredClone__default = /*#__PURE__*/_interopDefaultLegacy(structuredClone);

function deserialize(originalResponse, options = {}) {
const response = structuredClone__default["default"](originalResponse);

if (!options) {
options = {};
}

const included = response.included || [];

if (Array.isArray(response.data)) {
return response.data.map(data => {
return parseJsonApiSimpleResourceData(data, included, false);
});
} else {
return parseJsonApiSimpleResourceData(response.data, included, false);
}
}

function parseJsonApiSimpleResourceData(data, included, useCache, options) {
if (!included.cached) {
included.cached = {};
}

if (!(data.type in included.cached)) {
included.cached[data.type] = {};
}

if (useCache && data.id in included.cached[data.type]) {
return included.cached[data.type][data.id];
}

const attributes = data.attributes || {};
const resource = attributes;
resource.id = data.id;
included.cached[data.type][data.id] = resource;

if (data.relationships) {
for (const relationName of Object.keys(data.relationships)) {
const relationRef = data.relationships[relationName];

if (Array.isArray(relationRef.data)) {
const items = [];
relationRef.data.forEach(relationData => {
const item = findJsonApiIncluded(included, relationData.type, relationData.id);
items.push(item);
});
resource[relationName] = items;
} else if (relationRef && relationRef.data) {
resource[relationName] = findJsonApiIncluded(included, relationRef.data.type, relationRef.data.id);
} else {
resource[relationName] = null;
}
}
}

return resource;
}

function findJsonApiIncluded(included, type, id, options) {
let found = null;
included.forEach(item => {
if (item.type === type && item.id === id) {
found = parseJsonApiSimpleResourceData(item, included, true);
}
});

if (!found) {
found = {
id
};
}

return found;
}

function filterDeprecatedElements(elements) {
const els = [];
elements.forEach(element => {
var _element$nested_eleme, _element$essences;

if (((_element$nested_eleme = element.nested_elements) === null || _element$nested_eleme === void 0 ? void 0 : _element$nested_eleme.length) > 0) {
element.nested_elements = filterDeprecatedElements(element.nested_elements);
}

if (((_element$essences = element.essences) === null || _element$essences === void 0 ? void 0 : _element$essences.length) > 0) {
element.essences = element.essences.filter(essence => {
return !essence.deprecated;
});
}

if (!element.deprecated) {
els.push(element);
}
});
return els;
} // Returns deserialized page without deprecated content


function deserializePage(pageData) {
const page = deserialize(pageData);
page.elements = filterDeprecatedElements(page.elements);
return page;
} // Returns deserialized pages without deprecated content

function deserializePages(pagesData) {
const pages = deserialize(pagesData);
pages.forEach(page => {
page.elements = filterDeprecatedElements(page.elements);
});
return pages;
}

exports.deserialize = deserialize;
exports.deserializePage = deserializePage;
exports.deserializePages = deserializePages;
Loading

0 comments on commit c7d31a2

Please sign in to comment.