Skip to content

Commit

Permalink
#38: Wip: why CORS?
Browse files Browse the repository at this point in the history
  • Loading branch information
espen42 committed Sep 1, 2021
1 parent dc0832c commit 6b968f5
Show file tree
Hide file tree
Showing 15 changed files with 282 additions and 79 deletions.
22 changes: 6 additions & 16 deletions hmdb/src/main/resources/controllers/_graphql.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
const guillotineLib = require('/lib/guillotine');
const graphqlPlaygroundLib = require('/lib/graphql-playground');
const libGraphQl = require('/lib/graphql');
const schema = require('../guillotine/schema/schema');
const { CORS_HEADERS } = require("../lib/headless/cors-headers");

//──────────────────────────────────────────────────────────────────────────────
// Constants
//──────────────────────────────────────────────────────────────────────────────
const CORS_HEADERS = {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Origin': '*'
};

//──────────────────────────────────────────────────────────────────────────────
// Methods
Expand Down Expand Up @@ -39,21 +30,20 @@ exports.get = function (req) {
};
};

//const schema = guillotineLib.createSchema();


exports.post = function (req) {

let input = JSON.parse(req.body);

//log.info("--------------> Query:\n" + input.query);
const result = libGraphQl.execute(schema, input.query, input.variables);
// log.info("<-------------- Result:{\n" + JSON.stringify(result, null, 2));
let params = {
query: input.query,
variables: input.variables
};

return {
contentType: 'application/json',
headers: CORS_HEADERS,
body: result
body: guillotineLib.execute(params)
};
};

Expand Down
10 changes: 9 additions & 1 deletion hmdb/src/main/resources/controllers/contentapi/_content.es6
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@

const portalLib = require('/lib/xp/portal');
const { getContentData } = require('../../lib/headless/contentapi/contentdata');
const { CORS_HEADERS } = require("../../lib/headless/cors-headers");

exports.options = function () {
return {
contentType: 'text/plain;charset=utf-8',
headers: CORS_HEADERS
};
};

const handlePost = (req) => {
// query: HIGHLY RECOMMENDED: supply a query to override the fallback catch-all query with a BETTER SCALING, content-type-specific one.
Expand Down Expand Up @@ -33,4 +41,4 @@ const handlePost = (req) => {
exports.post = handlePost;

// FIXME: only for testing, remove.
exports.get = handlePost;
//exports.get = handlePost;
17 changes: 16 additions & 1 deletion hmdb/src/main/resources/controllers/contentapi/_contentbase.es6
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@

const portalLib = require('/lib/xp/portal');
const { getContentBase } = require('../../lib/headless/contentapi/contentbase');
const { CORS_HEADERS } = require("../../lib/headless/cors-headers");

log.info("CORS_HEADERS (" +
(Array.isArray(CORS_HEADERS) ?
("array[" + CORS_HEADERS.length + "]") :
(typeof CORS_HEADERS + (CORS_HEADERS && typeof CORS_HEADERS === 'object' ? (" with keys: " + JSON.stringify(Object.keys(CORS_HEADERS))) : ""))
) + "): " + JSON.stringify(CORS_HEADERS, null, 2)
);

exports.options = function () {
return {
contentType: 'text/plain;charset=utf-8',
headers: CORS_HEADERS
};
};

const handlePost = (req) => {
// idOrPath (mandatory if no override query is used): used in the default query. Can be a valid content UUID, or a (full) content path, eg. /mysite/persons/someone. Can be supplied direct param as here, or as part of the variables param (direct param has prescendence)
Expand Down Expand Up @@ -34,4 +49,4 @@ const handlePost = (req) => {
exports.post = handlePost;

// FIXME: only for testing, remove.
exports.get = handlePost;
//exports.get = handlePost;
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ exports.getContentBase = (siteId, branch, idOrPath, query, variables = {}, maxCh
}

return branchInvalidError400(branch) ||
idOrPathOrQueryInvalidError400(variables, query, 'No query was provided, and no id or path (iOrPath)') ||
idOrPathOrQueryInvalidError400(variables, query, 'No query was provided, and no id or path (idOrPath)') ||
executeResult(siteId, branch, query || getContentBaseQuery(variables.maxChildren), variables);
};
7 changes: 5 additions & 2 deletions hmdb/src/main/resources/lib/headless/contentapi/execute.es6
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
const { contentNotFoundError404 } = require('validation');
const {contentNotFoundError404} = require('validation');
const guillotineLib = require('/lib/guillotine');
const {CORS_HEADERS} = require("../cors-headers");



exports.executeResult = (siteId, branch, query, variables) => {
// TODO: app repo is targeted - should that be overridable?
const content = guillotineLib.execute({ query, variables, siteId, branch });
const content = guillotineLib.execute({query, variables, siteId, branch});

return contentNotFoundError404(content, variables, query) ||
{
status: 200,
body: content,
contentType: 'application/json',
headers: CORS_HEADERS
};
};
5 changes: 5 additions & 0 deletions hmdb/src/main/resources/lib/headless/cors-headers.es6
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.CORS_HEADERS = {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Origin': '*'
};
38 changes: 38 additions & 0 deletions next/enonic.connection.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const project = 'hmdb'; // <-- project identifier in path, e.g. 'default' in the URL <domain>/site/default/master
const appKey = "com.enonic.nextpoc.hmdb"; // <-- full app key = appName in hmdb/gradle.properties

const appKeyUnderscored = appKey.replace(/\./g, '_');
const appKeyDashed = appKey.replace(/\./g, '-');

const apiDomain = "http://localhost:8080";

const apiContentBase = '_contentbase';
const apiContentFull = '_content';

const siteRootUrlMaster = `${apiDomain}/site/${project}/master`;
const siteRootUrlDraft = `${apiDomain}/site/${project}/draft`;

// appName is the content _name of the root site content-item:
const contentApiUrlGetters = {
master: {
base: (appName) => `${siteRootUrlMaster}/${appName}/${apiContentBase}`,
full: (appName) => `${siteRootUrlMaster}/${appName}/${apiContentFull}`
},
draft: {
base: (appName) => `${siteRootUrlDraft}/draft/${appName}/${apiContentBase}`,
full: (appName) => `${siteRootUrlDraft}/draft/${appName}/${apiContentFull}`
}
};

module.exports = {
project,
appKey,
appKeyUnderscored,
appKeyDashed,
apiDomain,
apiContentBase,
apiContentFull,
siteRootUrlDraft,
siteRootUrlMaster,
contentApiUrlGetters
};
25 changes: 0 additions & 25 deletions next/enonic.connection.config.ts

This file was deleted.

23 changes: 23 additions & 0 deletions next/next.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
const {apiDomain} = require("./enonic.connection.config");

module.exports = {
reactStrictMode: true,
async headers() {
return [
{
source: '/:contentPath*',
headers: [
{
key: 'Access-Control-Allow-Origin',
value: "*",
},
{
key: 'Access-Control-Allow-Headers',
value: "Content-Type",
},
{
key: 'Access-Control-Allow-Methods',
value: "GET,POST,OPTIONS",
},
],
},
]
},
}
72 changes: 47 additions & 25 deletions next/src/pages/[[...contentPath]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {fetchContent} from "../shared/data";
import {contentApiUrlGetters} from "../../enonic.connection.config";
import Custom500 from './500';
import Custom404 from './404';
import React, { useState, useEffect } from 'react';

const {
full: getContentFullUrl,
Expand All @@ -28,59 +29,80 @@ type ContentApiBaseBody = {
};


const Page = ({error, contentBase}) => {
if (error) {
const Page = ({error, contentBase, freshen}) => {
/*if (error) {
switch (error.code) {
case 404:
return <Custom404 />
return <Custom404/>
case 500:
return <Custom500 message={error.message} />;
return <Custom500 message={error.message}/>;
}
}
}*/

// TODO: general fallback page. Resolve specific pages above
return <p>{JSON.stringify(contentBase)}</p>;
return <div onClick={freshen}>
<p>ContentBase: {JSON.stringify(contentBase)}</p>
<p>Error: {JSON.stringify(error)}</p>
</div>;
};

const Main = () => {
const [props, setProps] = useState({error: {}, contentBase: {}});

const freshen = async () => {
const p = await fetchContentBase(['hmdb', 'persons', 'keanu-reeves']);

console.log("p:", p);

// @ts-ignore
setProps(() => p);
};

return <Page error={props.error} contentBase={props.contentBase} freshen={freshen} />;
}

// this function also needs some serious refactoring, but for a quick and dirty
// proof of concept it does the job.
export const getServerSideProps = async ({params}: Context) => {
const idOrPath = "/" + params.contentPath.join("/");
/*
const appName = params.contentPath[0];
const contentFullUrl = getContentFullUrl(appName);
export const getServerSideProps = async ({params}: Context) => ({
props: await fetchContentBase(params.contentPath)
});
*/

export const fetchContentBase = async (contentPath: string[]) => {
const idOrPath = "/" + contentPath.join("/");
const appName = contentPath[0];
//const contentFullUrl = getContentFullUrl(appName);
const contentBaseUrl = getContentBaseUrl(appName);

const body: ContentApiBaseBody = {idOrPath};

const contentBase = await fetchContent(
const result = await fetchContent(
contentBaseUrl,
body
)
.then(json => {
if (!(json?.data?.guillotine || {}).get) {
if (!json?.data?.guillotine?.get) {
console.error('Data fetched from contentBase API:', json);
return { props: { error: { code: 404} } };
return { error: { code: 404 }};
}
})
.then(validJson => ({
// @ts-ignore
contentBase: validJson.data.guillotine.get
}))
.catch((err) => {
return {
props: {
error: {
code: 500,
message: err.message
}
error: {
code: 500,
message: err.message
}
};
});


return {
props: {
contentBase,
},
};
return result;
};

export default Page;
export default Main;

Loading

0 comments on commit 6b968f5

Please sign in to comment.