Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetching schema by url in library #34

Merged
merged 32 commits into from
Feb 7, 2019
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
46b9ba6
Add basic content: types, basic components and initial architecture
magicmatatjahu Nov 8, 2018
25731f5
Add Schema type and improve basic components
magicmatatjahu Nov 9, 2018
997a4e3
Add parser (validator and dereferencer for json and yaml)
magicmatatjahu Nov 9, 2018
5cce961
Add components: Messages, Schemas and Topics
magicmatatjahu Nov 9, 2018
9a1fa9d
Add Message component and improve Messages components
magicmatatjahu Nov 9, 2018
e376cc4
Big commit
magicmatatjahu Nov 12, 2018
6c53350
Improve components for better passing custom theme.
magicmatatjahu Nov 15, 2018
2f6321a
Improve kyma theme
magicmatatjahu Nov 16, 2018
07e637d
Audit packages
magicmatatjahu Nov 16, 2018
217d828
Add highlights in schemaExample component
magicmatatjahu Nov 16, 2018
159edd8
After review
magicmatatjahu Nov 18, 2018
45f63cb
Update package.json: add prettier and basic info of reposirtory
magicmatatjahu Nov 18, 2018
5de9286
Add tslint and prettier config file
magicmatatjahu Nov 18, 2018
6ed172b
Add Apache 2.0 license
magicmatatjahu Nov 18, 2018
28249d7
Setup tests configuration
magicmatatjahu Nov 20, 2018
fea738c
Split projects to two separate: playground and library and configure …
magicmatatjahu Nov 21, 2018
ed13f0b
Improve Playground app
magicmatatjahu Nov 22, 2018
e94b478
Add new mock and add function to remove null or undefined values from…
magicmatatjahu Nov 23, 2018
bf968c2
Add new License
magicmatatjahu Nov 23, 2018
c6995ef
Merge branch 'master' of https://github.com/kyma-incubator/asyncapi-r…
magicmatatjahu Nov 23, 2018
a8ee45f
Merge branch 'master' of https://github.com/kyma-incubator/asyncapi-r…
magicmatatjahu Nov 30, 2018
1e8f736
Merge branch 'master' of https://github.com/kyma-incubator/asyncapi-r…
magicmatatjahu Dec 4, 2018
c90c365
Merge branch 'master' of github.com:asyncapi/asyncapi-react
magicmatatjahu Dec 4, 2018
7e6627d
Merge branch 'master' of github.com:asyncapi/asyncapi-react
magicmatatjahu Dec 6, 2018
ad31428
Merge branch 'master' of github.com:asyncapi/asyncapi-react
magicmatatjahu Dec 9, 2018
3aa7465
Merge branch 'master' of github.com:asyncapi/asyncapi-react
magicmatatjahu Dec 9, 2018
6ba43f7
Merge branch 'master' of github.com:asyncapi/asyncapi-react
magicmatatjahu Jan 30, 2019
6da198c
Merge branch 'master' of github.com:asyncapi/asyncapi-react
magicmatatjahu Jan 31, 2019
ecb381f
Add feature to fetch schema from external resources in library package
magicmatatjahu Jan 31, 2019
a4b3f1d
Update readme.md for new prop
magicmatatjahu Jan 31, 2019
d09c1f5
After review
magicmatatjahu Jan 31, 2019
f9ac779
After Readme.md review
magicmatatjahu Feb 7, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ Check out this simple sandbox application that uses the asyncapi-react component

The list of props for the AsyncApi React component includes:

- **schema: string | AsyncApiInterface**
- **schema?: string | AsyncApiInterface**

The `schema` property is required and contains AsyncAPI specification. It should be one of the `string` or [`AsyncApiInterface`](./library/src/types.ts#L13) type. For more information on what it contains and what it should look like, read [AsyncAPI Specification](https://github.com/asyncapi/asyncapi#asyncapi-specification).
The `schema` property is optional and contains AsyncAPI specification. It should be one of the `string` or [`AsyncApiInterface`](./library/src/types.ts#L13) type. For more information on what it contains and what it should look like, read [AsyncAPI Specification](https://github.com/asyncapi/asyncapi#asyncapi-specification).

- **urlSchema?: FetchingSchemaInterface**

The `urlSchema` property is optional and contains url (required field) and requestOptions (optional field) for fetching schema from external resource.

- **theme?: Partial<ThemeInterface\>**

Expand All @@ -45,6 +49,8 @@ The list of props for the AsyncApi React component includes:

> **NOTE:** The `Partial<T>` type means that every field in the `T` type is optional.

> **NOTE:** You must pass `schema` or `urlSchema` to component for correct work of component.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about rewriting this copy?

Either schema or urlSchema prop must be present.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kazydek must check this, but thank you for your proposition :)


## Development

For information on how to set up a development environment, write and run tests, follow the naming and architecture convention defined for the project in the [Development Guide](./development-guide.md).
Expand Down
35 changes: 30 additions & 5 deletions library/src/containers/AsyncApi/AsyncApi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { ThemeProvider } from 'styled-components';
import { AsyncApi, SecurityScheme } from '../../types';
import { ThemeInterface, defaultTheme } from '../../theme';
import { ConfigInterface, defaultConfig } from '../../config';
import { parser, beautifier } from '../../helpers';
import {
parser,
beautifier,
FetchingSchemaInterface,
fetchSchema,
stringify,
} from '../../helpers';

import InfoComponent from '../Info/Info';
import Security from '../Security/Security';
Expand All @@ -16,7 +22,8 @@ import ErrorComponent from '../Error/Error';
import { AsyncApiWrapper } from './styled';

export interface AsyncApiProps {
schema: string | Object;
schema?: string | Object;
urlSchema?: FetchingSchemaInterface;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we enforce that either schema or urlSchema must be provided? I know it's possible with prop-types, but not sure about Typescript.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is possible by use type schema: string | Object | FetchingSchemaInterface. If developer pass FetchingSchemaInterface then we will fetch schema from url, otherwise we use schema :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't explain myself correctly. I mean having both schema and urlSchema, like it's right now, but enforcing in the code the rule of having just one of them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented my proposition from second comment in this thread. Please see: https://github.com/asyncapi/asyncapi-react/pull/34/files#diff-2fa873daa631d9246738398633704fd9R25

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I love this solution. Just one question: I see it says string | Object | FetchSchemaInterface, will it always fallback into Object? Saying because an object of the form FetchSchemaInterface is also an object, right? Or will typescript take care of this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks :) You can pass schema as string (json or yaml), or Object (this is reference to AsyncAPIInterface) or FetchSchemaInterface. I agree with you that FetchSchemaInterface is also a Object, but Object with appropriate fields, so if dev pass Object as FetchSchemaInterface to component then component will execute whole code as FetchSchemaInterface, if pass as Object, then code validate this Object as AsyncApi and show errors if this spec is invalid :) You have to look at it in terms of static typing, not dynamic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. Thanks! :)

theme?: Partial<ThemeInterface>;
config?: Partial<ConfigInterface>;
}
Expand Down Expand Up @@ -53,12 +60,28 @@ class AsyncApiComponent extends Component<AsyncApiProps, AsyncApiState> {
}

async componentWillMount() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads up componentWillMount is deprecated. Check out: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

componentWillMount and other will be deprecated on >= 17.0 versions. We use at the moment 16.6.3 version of React and we don't see any warnings related to the use of these lifecycles, but I will think whether to change it now or in the next PR.

this.prepareSchema(this.props.schema);
const { schema, urlSchema } = this.props;

if (schema) {
await this.prepareSchema(schema);
} else if (urlSchema) {
await this.prepareSchema(await fetchSchema(urlSchema));
}
}

async componentWillReceiveProps(nextProps: AsyncApiProps) {
if (nextProps.schema !== this.props.schema) {
this.prepareSchema(nextProps.schema);
const { schema, urlSchema } = nextProps;

if (schema && schema !== this.props.schema) {
await this.prepareSchema(schema);
} else if (urlSchema) {
const stringifiedUrlSchema = stringify(urlSchema);
if (
stringifiedUrlSchema &&
stringifiedUrlSchema !== stringify(this.props.urlSchema)
) {
await this.prepareSchema(await fetchSchema(urlSchema));
}
}
}

Expand Down Expand Up @@ -98,6 +121,8 @@ class AsyncApiComponent extends Component<AsyncApiProps, AsyncApiState> {

if (!(validatedSchema && validated)) return null;

console.log(validatedSchema);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it forgotten here?

Copy link
Member Author

@magicmatatjahu magicmatatjahu Jan 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah :D I always forget about console.logs in my code. Thanks!


return (
<ThemeProvider theme={concatenatedTheme}>
<AsyncApiWrapper>
Expand Down
19 changes: 19 additions & 0 deletions library/src/helpers/fetchSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface FetchingSchemaInterface {
url: string;
requestOptions?: RequestInit;
}

const defaultRequestOptions: RequestInit = {
method: 'GET',
};

export const fetchSchema = async ({
url,
requestOptions = defaultRequestOptions,
}: FetchingSchemaInterface): Promise<any> => {
return fetch(url, requestOptions).then(handleResponse);
};

function handleResponse(response: any) {
return response.text().then((data: string) => data);
}
4 changes: 3 additions & 1 deletion library/src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './parser';
export * from './beautifier';
export * from './beautifier';
export * from './fetchSchema';
export * from './json-parser';
19 changes: 19 additions & 0 deletions library/src/helpers/json-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const parse = <T extends {}>(str?: string): T => {
if (!str) return {} as T;

try {
return JSON.parse(str) as T;
} catch (e) {
return {} as T;
}
};

export const stringify = <T extends {}>(content?: T): string => {
if (!content) '';

try {
return JSON.stringify(content);
} catch (e) {
return '';
}
};
3 changes: 2 additions & 1 deletion library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AsyncApi from './containers/AsyncApi/AsyncApi';
export { AsyncApiProps } from './containers/AsyncApi/AsyncApi';
export { ThemeInterface } from './theme/theme';
export { ConfigInterface } from './config/config';
export { FetchingSchemaInterface } from './helpers';
export { AsyncApi as AsyncApiInterface } from './types';

export default AsyncApi
export default AsyncApi;
8 changes: 6 additions & 2 deletions playground/src/common/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
export const parse = <T extends {}>(str: string): T => {
export const parse = <T extends {}>(str?: string): T => {
if (!str) return {} as T;

try {
return JSON.parse(str) as T;
} catch (e) {
return {} as T;
}
};

export const stringify = <T extends {}>(content: T): string => {
export const stringify = <T extends {}>(content?: T): string => {
if (!content) '';

try {
return JSON.stringify(content);
} catch (e) {
Expand Down