-
-
Notifications
You must be signed in to change notification settings - Fork 694
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into bami/marketing-report
- Loading branch information
Showing
16 changed files
with
320 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
--- | ||
title: "November and December Community Update And AsyncAPI Conf in Paris 2024" | ||
date: 2024-12-16T06:00:00+01:00 | ||
type: Communication | ||
tags: | ||
- Project Status | ||
cover: /img/posts/2024-blog-banner/blog-banner-december.webp | ||
authors: | ||
- name: Thulisile Sibanda | ||
photo: /img/avatars/thulieblack.webp | ||
link: https://www.linkedin.com/in/v-thulisile-sibanda/ | ||
byline: Community Builder and Open Source Fanatic! | ||
excerpt: 'November and December Community Update And Paris Conference Summary' | ||
featured: true | ||
--- | ||
I can't believe we are in the final weeks of the year, and it has been an eventful one. As a community, we have experienced both proud and painful moments, celebrated our victories, and faced challenges and losses. However, in the end, we overcame those difficulties and emerged stronger and better. | ||
|
||
Although this summary is a bit later than usual, I am excited to share the details of what happened in November and December and the highlights from the last conference of the year, which took place in Paris. | ||
|
||
## AsyncAPI Community Building and Maintenance Goals Proposal 2025 | ||
|
||
The 2025 community building and maintenance goals proposal is currently open for discussion and will soon be put to a vote for TSC members. We would love your thoughts and suggestions, particularly when solving our community's challenges. | ||
[Please take a moment to review the open PR related to the AsyncAPI Community Building Goals for 2025](https://github.com/asyncapi/community/pull/1575) to participate in the discussion and share your ideas and solutions. | ||
|
||
## AsyncAPI Conf in Paris 2024 | ||
|
||
The AsyncAPI Conf was back again in Paris this December, thanks to [Mehdi Medjaoui](https://www.linkedin.com/in/mehdimedjaoui/) and the amazing team at [APIdays](https://www.apidays.global/) for hosting and sponsoring the venue. We participated in the three-day event, celebrating a year of the `API Standards` booth alongside friends from OpenAPI, JSON Schema, and GraphQL. Special thanks to all the members of the AsyncAPI community who could join the conference and help at the booth: [Hugo Guerrero](https://www.linkedin.com/in/hugoguerrero/), [Fran Méndez](https://www.linkedin.com/in/fmvilas/), [Richard Coppen](https://www.linkedin.com/in/richard-coppen/), [Hari Krishnan](https://www.linkedin.com/in/harikrishnan83/), and [Lukasz Gornicki](https://www.linkedin.com/in/lukasz-gornicki-a621914/). | ||
|
||
The AsyncAPI Conf track took place on the 3rd day of the conference, featuring an impressive lineup of sessions that attracted a diverse audience. The event was consistently packed, with attendees engaged throughout the day. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/full-room.webp" | ||
caption="Attendees engaged through the sessions." | ||
className="text-center" | ||
/> | ||
|
||
[Fran Méndez](https://www.linkedin.com/in/fmvilas/) and [Lukasz Gornicki](https://www.linkedin.com/in/lukasz-gornicki-a621914/) started the track with a welcome speech and mentioned that AsyncAPI recently celebrated its 8th anniversary in November. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/lukasz-and-fran.webp" | ||
caption="Fran and Lukasz during the welcome speech." | ||
className="text-center" | ||
/> | ||
|
||
[Naresh Jain](https://www.linkedin.com/in/nareshjain/) and [Pierre Gauthier](https://www.linkedin.com/in/pierre-gauthier-46080916/) presented their keynote on `TMForum's AsyncAPI for a New Era of Event-Driven Architecture`. During the session, Pierre announced TMForum adopts AsyncAPI as a standard, with over 120 telco APIs already in production. TMForum has around 800 telco companies, and they will implement all APIs in an async manner, extensively utilizing the request-reply pattern. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/naresh-and-pierre.webp" | ||
caption="Naresh and Pierre presenting their keynote." | ||
className="text-center" | ||
/> | ||
|
||
[Frank Kilcommins](https://www.linkedin.com/in/frank-kilcommins) demonstrated how treating API governance as an enabler unlocks the ability to deliver compelling developer experiences for producers and consumers in event-driven architecture (EDA). | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/frank.webp" | ||
caption="Frank presenting on API Governance for EDA: Unlocking Developer Experience with AsyncAPI." | ||
className="text-center" | ||
/> | ||
|
||
[Leonid Lukyanov](https://www.linkedin.com/in/leonid-lukyanov/) shared how EDAs introduce new data models, protocols, and APIs not found in the traditional REST/CRUD application stack. And how one can abstract these elements to make them feel familiar to application developers, allowing them to create streaming applications seamlessly. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/leonid.webp" | ||
caption="Leonid presenting on Reimagining Streaming Apps with AsyncAPI and Postgres." | ||
className="text-center" | ||
/> | ||
|
||
[Hugo Guerrero](https://www.linkedin.com/in/hugoguerrero/) then shared how the AsyncAPI Initiative is not only in charge of the specification but has created open-source projects to make it easier for developers to work with the specification documents. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/hugo.webp" | ||
caption="Hugo presenting on Using the AsyncAPI Ecosystem for Your Event-Driven Architecture." | ||
className="text-center" | ||
/> | ||
|
||
[Julien Testut](https://www.linkedin.com/in/julientestut/) and [Alessandro Cagnetti](https://www.linkedin.com/in/cagnetti/) shared how organizations can harness the full potential of event-driven integration by leveraging GoldenGate Data Streams, AsyncAPI, and Solace PubSub+ Event Mesh. They shared a great use case for AI and how it can be trained real-time and standardized with AsyncAPI. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/julien-and-alessandro.webp" | ||
caption="Julien and Alessandro presenting on Streaming Data Events Into An AI Cognitive Event Mesh Using AsyncAPI." | ||
className="text-center" | ||
/> | ||
|
||
[Annegret Junker](https://www.linkedin.com/in/dr-annegret-junker-141a99a4/) explained how to design effective asynchronous APIs by using an API-first approach. The importance of defining Kafka topics and structuring your definitions. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/annegret.webp" | ||
caption="Annegret presenting on AsyncAPI for Kafka." | ||
className="text-center" | ||
/> | ||
|
||
|
||
[Jonathan Michaux](https://www.linkedin.com/in/jmcx/) spoke on how leveraging AI agents with AsyncAPI can create conversational interfaces that dynamically interact with event streams and asynchronous messaging systems. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/jonathan.webp" | ||
caption="Jonathan presenting on AI Agents Meet AsyncAPI: Conversational Interfaces for Event Streams." | ||
className="text-center" | ||
/> | ||
|
||
[Hari Krishnan](https://www.linkedin.com/in/harikrishnan83) and [Joel Rosario](https://www.linkedin.com/in/joel-c-rosario/) touched on leveraging the AsyncAPI specification as an executable contract and how to isolate and test each component within an EDA. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/hari-and-joel.webp" | ||
caption="Hari and Joel presenting on Contract-Driven Development for Event-Driven Architectures." | ||
className="text-center" | ||
/> | ||
|
||
[Laurent Broudoux](https://www.linkedin.com/in/laurentbroudoux/) and [Hugo Guerrero](https://www.linkedin.com/in/hugoguerrero/) ended the day by explaining how to use Microcks to provide a solution for mocking and contract-testing your async APIs without extensive coding and empowering you to build extensive and reliable integration tests. | ||
|
||
<Figure | ||
src="/img/posts/paris-conf-2024/laurent-and-hugo.webp" | ||
caption="Laurent and Hugo presenting From Nightmares to Sweet Dreams: Conquering AsyncAPI Testing!." | ||
className="text-center" | ||
/> | ||
|
||
## Technical Steering Committee | ||
|
||
Part of doing mentorships is witnessing the growth within the community, and we are excited to welcome [Ashmit Jagtap](https://www.linkedin.com/in/ashmit-jagtap) as our newest addition to the maintainers list and TSC member. We are proud of the work you have done so far. | ||
|
||
<Profiles profiles={[ | ||
{ | ||
name: 'Ashmit Jagtap', | ||
avatar: 'https://avatars.githubusercontent.com/u/69006513?v=4', | ||
link: 'https://www.github.com/ashmit-coder' | ||
} | ||
]} /> | ||
|
||
## Final Remarks | ||
|
||
It's been a privilege to write the AsyncAPI monthly summary blog consistently. As this is the final blog for the year, I am genuinely grateful for the opportunity to serve and continue supporting the community. | ||
|
||
As we approach the holidays, I wish everyone happy holidays and a fantastic 2025. | ||
|
||
I'll be back next year with an overall review summary of 2024. | ||
|
||
**Until then, stay safe, and happy holidays!** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
const fs = require('fs').promises; | ||
const path = require('path'); | ||
const os = require('os'); | ||
const { | ||
isValidURL, | ||
main, | ||
validateBlogs, | ||
validateDocs, | ||
checkMarkdownFiles | ||
} = require('../../scripts/markdown/check-markdown'); | ||
|
||
describe('Frontmatter Validator', () => { | ||
let tempDir; | ||
let mockConsoleError; | ||
let mockProcessExit; | ||
|
||
beforeEach(async () => { | ||
mockConsoleError = jest.spyOn(console, 'error').mockImplementation(); | ||
mockProcessExit = jest.spyOn(process, 'exit').mockImplementation(); | ||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test-config')); | ||
}); | ||
|
||
afterEach(async () => { | ||
mockConsoleError.mockRestore(); | ||
mockProcessExit.mockRestore(); | ||
await fs.rm(tempDir, { recursive: true, force: true }); | ||
}); | ||
|
||
it('validates authors array and returns specific errors', async () => { | ||
const frontmatter = { | ||
title: 'Test Blog', | ||
date: '2024-01-01', | ||
type: 'blog', | ||
tags: ['test'], | ||
cover: 'cover.jpg', | ||
authors: [{ name: 'John' }, { photo: 'jane.jpg' }, { name: 'Bob', photo: 'bob.jpg', link: 'not-a-url' }] | ||
}; | ||
|
||
const errors = validateBlogs(frontmatter); | ||
expect(errors).toEqual(expect.arrayContaining([ | ||
'Author at index 0 is missing a photo', | ||
'Author at index 1 is missing a name', | ||
'Invalid URL for author at index 2: not-a-url' | ||
])); | ||
}); | ||
|
||
it('validates docs frontmatter for required fields', async () => { | ||
const frontmatter = { title: 123, weight: 'not-a-number' }; | ||
const errors = validateDocs(frontmatter); | ||
expect(errors).toEqual(expect.arrayContaining([ | ||
'Title is missing or not a string', | ||
'Weight is missing or not a number' | ||
])); | ||
}); | ||
|
||
it('checks for errors in markdown files in a directory', async () => { | ||
await fs.writeFile(path.join(tempDir, 'invalid.md'), `---\ntitle: Invalid Blog\n---`); | ||
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(); | ||
|
||
await checkMarkdownFiles(tempDir, validateBlogs); | ||
|
||
expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Errors in file invalid.md:')); | ||
mockConsoleLog.mockRestore(); | ||
}); | ||
|
||
it('returns multiple validation errors for invalid blog frontmatter', async () => { | ||
const frontmatter = { | ||
title: 123, | ||
date: 'invalid-date', | ||
type: 'blog', | ||
tags: 'not-an-array', | ||
cover: ['not-a-string'], | ||
authors: { name: 'John Doe' } | ||
}; | ||
const errors = validateBlogs(frontmatter); | ||
|
||
expect(errors).toEqual([ | ||
'Invalid date format: invalid-date', | ||
'Tags should be an array', | ||
'Cover must be a string', | ||
'Authors should be an array']); | ||
}); | ||
|
||
it('logs error to console when an error occurs in checkMarkdownFiles', async () => { | ||
const invalidFolderPath = path.join(tempDir, 'non-existent-folder'); | ||
|
||
await expect(checkMarkdownFiles(invalidFolderPath, validateBlogs)) | ||
.rejects.toThrow('ENOENT'); | ||
|
||
expect(mockConsoleError.mock.calls[0][0]).toContain('Error in directory'); | ||
}); | ||
|
||
it('skips the "reference/specification" folder during validation', async () => { | ||
const referenceSpecDir = path.join(tempDir, 'reference', 'specification'); | ||
await fs.mkdir(referenceSpecDir, { recursive: true }); | ||
await fs.writeFile(path.join(referenceSpecDir, 'skipped.md'), `---\ntitle: Skipped File\n---`); | ||
|
||
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(); | ||
|
||
await checkMarkdownFiles(tempDir, validateDocs); | ||
|
||
expect(mockConsoleLog).not.toHaveBeenCalledWith(expect.stringContaining('Errors in file reference/specification/skipped.md')); | ||
mockConsoleLog.mockRestore(); | ||
}); | ||
|
||
it('logs and rejects when an exception occurs while processing a file', async () => { | ||
const filePath = path.join(tempDir, 'invalid.md'); | ||
await fs.writeFile(filePath, `---\ntitle: Valid Title\n---`); | ||
|
||
const mockReadFile = jest.spyOn(fs, 'readFile').mockRejectedValue(new Error('Test readFile error')); | ||
|
||
await expect(checkMarkdownFiles(tempDir, validateBlogs)).rejects.toThrow('Test readFile error'); | ||
expect(mockConsoleError).toHaveBeenCalledWith( | ||
expect.stringContaining(`Error in directory`), | ||
expect.any(Error) | ||
); | ||
|
||
mockReadFile.mockRestore(); | ||
}); | ||
|
||
it('should handle main function errors and exit with status 1', async () => { | ||
jest.spyOn(fs, 'readdir').mockRejectedValue(new Error('Test error')); | ||
|
||
await main(); | ||
|
||
expect(mockProcessExit).toHaveBeenCalledWith(1); | ||
|
||
expect(mockConsoleError).toHaveBeenCalledWith( | ||
'Failed to validate markdown files:', | ||
expect.any(Error) | ||
); | ||
}); | ||
|
||
it('should handle successful main function execution', async () => { | ||
|
||
await main(); | ||
|
||
expect(mockConsoleError).not.toHaveBeenCalledWith(); | ||
}); | ||
|
||
it('should return true or false for URLs', () => { | ||
expect(isValidURL('http://example.com')).toBe(true); | ||
expect(isValidURL('https://www.example.com')).toBe(true); | ||
expect(isValidURL('ftp://ftp.example.com')).toBe(true); | ||
expect(isValidURL('invalid-url')).toBe(false); | ||
expect(isValidURL('/path/to/file')).toBe(false); | ||
expect(isValidURL('www.example.com')).toBe(false); | ||
}); | ||
|
||
}); |