DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Open Source

Open source refers to non-proprietary software that allows anyone to modify, enhance, or view the source code behind it. Our resources enable programmers to work or collaborate on projects created by different teams, companies, and organizations.

icon
Latest Premium Content
Trend Report
Enterprise Application Security
Enterprise Application Security
Refcard #357
NoSQL Migration Essentials
NoSQL Migration Essentials
Refcard #297
GitOps for Kubernetes
GitOps for Kubernetes

DZone's Featured Open Source Resources

A Hands-On Guide To OpenTelemetry: Intro to Observability

A Hands-On Guide To OpenTelemetry: Intro to Observability

By Eric D. Schabell DZone Core CORE
Are you ready to start your journey on the road to collecting telemetry data from your applications? Great observability begins with great instrumentation! In this series, you'll explore how to adopt OpenTelemetry (OTel) and how to instrument an application to collect tracing telemetry. You'll learn how to leverage out-of-the-box automatic instrumentation tools and understand when it's necessary to explore more advanced manual instrumentation for your applications. By the end of this series, you'll have an understanding of how telemetry travels from your applications to the OpenTelemetry Collector, and be ready to bring OpenTelemetry to your future projects. Everything discussed here is supported by a hands-on, self-paced workshop authored by Paige Cruze. This first article takes time to lay the foundation, defining common observability and monitoring terms that help us gain an understanding of the role of OpenTelemetry and its components. This introduction needs to start with some really basic definitions so that we're all on the same page when we move on to more complex topics. Defining Our Needs First, there is the term observability. This is how effectively you can understand system behavior from the outside using the data that the system generates. Monitoring is a bit more subtle of a term, where we are continuously in the process of watching and tracking system health based on a pre-defined set of data. This often is done using dashboards that represent queries on that set of data. When we talk about data, we are actually talking about telemetry, which is the process of recording and sending data from remote components to a backend. Examples of telemetry are data types that include metrics, logs, events, and traces. Finally, we have to look at instrumentation. This is the actual code that records and measures the behavior of an application or infrastructure component. There are two types of instrumentation at which we'll be looking: auto-instrumentation and manual instrumentation. The first is provided out of the box by the provided instrumentation library, usually just by adding its usage and flipping the switch. The second is achieved by custom code added to applications, usually narrowing the scope or specific focus of your data needs. What Is OpenTelemetry? The project OTel has been part of the Cloud Native Computing Foundation (CNCF) since 2019 and was born from the merging of the projects OpenCensus and OpenTracing. OTel is a set of standardized vendor-agnostic Software Developer Kits (SDKs), Application Programming Interfaces (APIs), and other tools for ingesting, transforming, and sending telemetry to observability back-ends. Below is a basic architecture of OTel showing a typical cloud-native environment with microservices, infrastructure components, and instrumented client applications pushing telemetry data through the OTel Collector to eventual observability backends. Included in the OTel tooling are the OTel API and SDK, shown being used in the microservices for auto-instrumentation and manually instrumenting those services. The API defines the data types available to us and how to generate our telemetry data. When it becomes necessary to create a language-specific implementation of the API, configuration, data processing, and exporting. As of this writing, the following is the status listing for specific language API/SDK support. See the OTel documentation for current details on specific language support: We can also make use of the client instrumentation libraries. Check out the 770+ that are available in the OTel Registry for instrumenting our specific needs. It's always important to include in the introduction section what a technology can't do. The first one is that OTel is NOT only a tracing tool, only being able to collect tracing data. The specifications have been expanded to include metrics and logs processing. OTel does NOT provide for any telemetry backend or storage systems. It leaves this to other projects such as Jaeger and Prometheus. Finally, OTel does NOT provide any sort of observability UI. It focuses on the generation, collection, management, and export of telemetry. OTel leaves the storing, querying, and visualizing of telemetry data to other projects or vendors. The Collector The OpenTelemetry Collector is a proxy that can receive, process, and export telemetry data. It is a vendor-agnostic implementation that supports open-source observability data formats such as the CNCF projects Jaeger, Prometheus, Fluent Bit, and more. The collector does this using the OpenTelemetry Protocol (OTLP), a specification describing the encoding, transportation, and delivery mechanism of telemetry data between telemetry sources, intermediate nodes such as collectors, and telemetry backends. Simply stated, OTLP is a general-purpose telemetry data delivery protocol. Within OTel there is the concept of an OTel Resource, which represents the entity producing telemetry as resource attributes. Imagine a service running in a container on Kubernetes and producing telemetry such as service.name, pod.name, namespace, etc. All of these attributes can be included in the resource. This resource information is used to investigate interesting behavior, such as latency in your system being narrowed down to a specific container, pod, or service. Instrumentation Types There are three types of instrumentation that you will be exploring listed here. They each include a code example from the previously mentioned hands-on workshop application. An automatic agent runs alongside the application and adds instrumentation without code changes. # Nothing to see here, no code changes to my application, # agent injects instrumentation at runtime. # from flask import Flask, request app = Flask(__name__) @app.route("/server_request") def server_request(): print(request.args.get("param")) return "served" if __name__ == "__main__": app.run(port=8082) Programmatic is a mix of both, where you pull in pre-instrumented dependencies and manually add metadata (e.g., labels). # Use framework specific instrumentation library to capture # basic method calls, requiring configuration and code changes. # from flask import Flask, request from opentelemetry.instrumentation.flask import FlaskInstrumentor from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchSpanProcessor, ConsoleSpanExporter, ) from opentelemetry.trace import get_tracer_provider, set_tracer_provider set_tracer_provider(TracerProvider()) get_tracer_provider().add_span_processor( BatchSpanProcessor(ConsoleSpanExporter()) ) instrumentor = FlaskInstrumentor() app = Flask(__name__) instrumentor.instrument_app(app) @app .route("/server_request") def server_request(): print(request.args.get("param")) return "served" if __name__ == "__main__": app.run(port= 8082) With manual, you set up an observability library and add instrumentation code. # Requires configuring OpenTelemetry libraries and # instrumenting every method call you care about. # from flask import Flask, request from opentelemetry.instrumentation.wsgi import collect_request_attributes from opentelemetry.propagate import extract from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchSpanProcessor, ConsoleSpanExporter, ) from opentelemetry.trace import ( SpanKind, get_tracer_provider, set_tracer_provider, ) app = Flask(__name__) set_tracer_provider(TracerProvider()) tracer = get_tracer_provider().get_tracer(__name__) get_tracer_provider().add_span_processor( BatchSpanProcessor(ConsoleSpanExporter()) ) @app .route("/server_request") def server_request(): with tracer.start_as_current_span( "server_request", context=extract(request.headers), kind=SpanKind.SERVER, attributes=collect_request_attributes(request.environ), ): print(request.args.get("param")) return "served" if __name__ == "__main__": app.run(port= 8082) These three examples use code from a Python application that you can explore in the provided hands-on workshop. What's Next? This article defined some common observability and monitoring terms, helping you gain an understanding of the role OpenTelemetry and its components play in observability solutions. Next up, installing OpenTelemetry on our local machine, configuring the SDK, running the demo application, and viewing trace data in the console. More
Cucumber and Spring Boot Integration: Passing Arguments To Step Definitions Explained

Cucumber and Spring Boot Integration: Passing Arguments To Step Definitions Explained

By Gunter Rotsaert DZone Core CORE
Cucumber is a tool that supports Behavior-Driven Development (BDD). In this blog, you will learn how to pass arguments to step definitions when using Cucumber and Spring Boot. Enjoy! Introduction In a previous post, Cucumber was introduced as a tool that supports Behavior-Driven Development (BDD). Some of the features were explained, but not how to pass arguments to step definitions. In this blog, you will learn how you can do so. The application under test is a Spring Boot application. You will also learn how you can integrate the Cucumber tests with Spring. The sources used in this blog are available on GitHub. Do check out the following references for extra information: Cucumber ExpressionsCucumber Configuration: Type Registry Prerequisites The prerequisites for this blog are: Basis Java knowledge - Java 21 is usedBasic Maven knowledgeBasic Spring Boot knowledgeBasic comprehension of BDDBasic knowledge of Cucumber (see the previous blog for an introduction) Application Under Test The application under test is a basic Spring Boot application. It consists of a Controller and a Service. The Controller serves a customer endpoint that implements an OpenAPI specification. The Service is a basic implementation, storing customers in a HashMap. A customer only has a first name and a last name, just to keep things simple. The API offers the following functionality: Creating a customerRetrieving the customer based on the customer IDRetrieving all customersDeleting all customers Spring Integration In order to enable the Spring integration, you add the following dependency to the pom: XML <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-spring</artifactId> <version>7.14.0</version> <scope>test</scope> </dependency> The Spring Boot application must be in a running state; therefore, you need to run the Cucumber tests with the @SpringBootTest annotation. This will start the application and you will be able to run Cucumber tests for it. In order to do so, you create a class CucumberSpringConfiguration. Add the @CucumberContextConfiguration annotation so that the Spring integration is enabled. The Spring Boot application starts on a random port; therefore, you store the port in a system property so that you will be able to use it when you need to call the API. Java @CucumberContextConfiguration @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class CucumberSpringConfiguration { @LocalServerPort private int port; @PostConstruct public void setup() { System.setProperty("port", String.valueOf(port)); } } The Cucumber step definitions will extend this class. Tests can be run via Maven: Shell $ mvn clean verify Test: Add Customer Using Arguments The Add Customer test will add a customer to the customer list and will verify that the customer is added to the list. The feature file is the following. Do note that the first name (John) and last name (Doe) are within quotes. This way, Cucumber is able to recognize a string argument. Plain Text Scenario: Add customer Given an empty customer list When customer 'John' 'Doe' is added Then the customer 'John' 'Doe' is added to the customer list The corresponding step definitions are the following. When: The first name and last name placeholders are represented with {string} and they are mapped as arguments to the method. This way, the arguments are accessible to the step definition.Then: In a similar way, the arguments are passed to the step definition. Java public class StepDefinitions extends CucumberSpringConfiguration { final int port = Integer.parseInt(System.getProperty("port")); final RestClient restClient = RestClient.create(); @Given("an empty customer list") public void an_empty_customer_list() { ResponseEntity<Void> response = restClient.delete() .uri("http://localhost:"+ port + "/customer") .retrieve() .toBodilessEntity(); } @When("customer {string} {string} is added") public void customer_firstname_lastname_is_added(String firstName, String lastName) { Customer customer = new Customer(firstName, lastName); ResponseEntity<Void> response = restClient.post() .uri("http://localhost:"+ port + "/customer") .contentType(APPLICATION_JSON) .body(customer) .retrieve() .toBodilessEntity(); assertThat(response.getStatusCode().is2xxSuccessful()).isTrue(); } @Then("the customer {string} {string} is added to the customer list") public void the_customer_first_name_last_name_is_added_to_the_customer_list(String firstName, String lastName) { List<Customer> customers = restClient.get() .uri("http://localhost:"+ port + "/customer") .retrieve() .body(new ParameterizedTypeReference<>() {}); assertThat(customers).contains(new Customer(firstName, lastName)); } ... } Note that the arguments are used to create a Customer object which is defined in the step definitions class. This class contains the fields, getters, setters, equals, and hashCode implementations. Java public static class Customer { private String firstName; private String lastName; ... } Test: Add Customers Using Arguments When you want to add several customers, you can chain the same step definition by means of an And using different arguments. The feature file is the following, the step definitions remain the same. Plain Text Scenario: Add customers Given an empty customer list When customer 'John' 'Doe' is added And customer 'David' 'Beckham' is added Then the customer 'John' 'Doe' is added to the customer list And the customer 'David' 'Beckham' is added to the customer list Test: Add Customer Using DataTable The previous tests all started with an empty customer list. The next test will add some data to the customer list as a starting point. You can, of course, use the step definition customer firstName lastName is added and invoke it multiple times, but you can also use a DataTable. The DataTable must be the last argument in a step definition. The feature file is the following and the DataTable is used in the Given-clause. Plain Text Scenario: Add customer to existing customers Given the following customers: | John | Doe | | David | Beckham | When customer 'Bruce' 'Springsteen' is added Then the customer 'Bruce' 'Springsteen' is added to the customer list In the implementation of the step definition, you now see that the arguments are passed as a DataTable. It is a table containing strings, so you need to parse the table yourself. Java @Given("the following customers:") public void the_following_customers(io.cucumber.datatable.DataTable dataTable) { for (List<String> customer : dataTable.asLists()) { customer_firstname_lastname_is_added(customer.get(0), customer.get(1)); } } Test: Add Customer Using Parameter Type In the previous test, you needed to parse the DataTable yourself. Wouldn’t it be great if the DataTable could be mapped immediately to a Customer object? This is possible if you define a parameter type for it. You create a parameter type customerEntry and annotate it with @DataTableType. You use the string arguments of a DataTable to create a Customer object. You do so in a class ParameterTypes, which is considered as best practice. Java public class ParameterTypes { @DataTableType public StepDefinitions.Customer customerEntry(Map<String, String> entry) { return new StepDefinitions.Customer( entry.get("firstName"), entry.get("lastName")); } } The feature file is identical to the previous one, only the step definition has changed in order to have a unique step definition. Plain Text Scenario: Add customer to existing customers with parameter type Given the following customers with parameter type: | John | Doe | | David | Beckham | When customer 'Bruce' 'Springsteen' is added Then the customer 'Bruce' 'Springsteen' is added to the customer list In the implementation of the step definition, you notice that the argument is not a DataTable anymore, but a list of Customer. Java @Given("the following customers with parameter type:") public void the_following_customers_with_parameter_type(List<Customer> customers) { for (Customer customer : customers) { customer_firstname_lastname_is_added(customer.getFirstName(), customer.getLastName()); } } Conclusion In this blog, you learned how to integrate Cucumber with a Spring Boot application and several ways to pass arguments to your step definitions - a powerful feature of Cucumber! More
Custom Health Checks in Spring Boot
Custom Health Checks in Spring Boot
By Sai Krishna Reddy Chityala
regreSSHion: Should We Panic About the New OpenSSH Vulnerability?
regreSSHion: Should We Panic About the New OpenSSH Vulnerability?
By Nikolai Mishin
Open-Source Dapr for Spring Boot Developers
Open-Source Dapr for Spring Boot Developers
By Thomas Vitale
7 Essential Tips for a Production ClickHouse Cluster
7 Essential Tips for a Production ClickHouse Cluster

ClickHouse is the fastest, most resource-efficient OLAP database which can query billions of rows in milliseconds and is trusted by thousands of companies for real-time analytics. Here are seven tips to help you spin up a production ClickHouse cluster and avoid the most common mistakes. Tip 1: Use Multiple Replicas While testing ClickHouse, it’s natural to deploy a configuration with only one host because you may not want to use additional resources or take on unnecessary expenses. There’s nothing wrong with this in a development or testing environment, but that can come at a cost if you want to use only one host in production. If there’s a failure and you only have one replica and a single host, you’re at risk of losing all your data. For production loads, you should use several hosts and replicate data across them. Not only does it ensure that data remains safe when a host fails, but also allows you to balance the user load on several hosts, which makes resource-intensive queries faster. Tip 2: Don’t Be Shy With RAM ClickHouse is fast, but its speed depends on available resources, especially RAM. You can see great performance when running a ClickHouse cluster with the minimum amount of RAM in a development or testing environment, but that may change when the load increases. In a production environment with a lot of simultaneous read and write operations, a lack of RAM will be more noticeable. If your ClickHouse cluster doesn’t have enough memory, it will be slower, and executing complex queries will take longer. On top of that, when ClickHouse is performing resource-intensive operations, it may compete with the OS itself for RAM, and that eventually leads to OOM, downtime, and data loss. Developers of ClickHouse recommend using at least 16 GB of RAM to ensure that the cluster is stable. You can opt for less memory, but only do so when you know that the load won’t be high. Tip 3: Think Twice When Choosing a Table Engine ClickHouse supports several table engines with different characteristics, but a MergeTree engine will most likely be ideal. Specialized tables are tailored for specific uses, but have limitations that may not be obvious at first glance. Log Family engines may seem ideal for logs, but they don’t support replication and their database size is limited. Table engines in the MergeTree family are the default choice, and they provide the core data capabilities that ClickHouse is known for. Unless you know for sure why you need a different table engine, use an engine from a MergeTree family, and it will cover most of your use cases. Tip 4: Don’t Use More Than Three Columns for the Primary Key Primary keys in ClickHouse don’t serve the same purpose as in traditional databases. They don’t ensure uniqueness, but instead define how data is stored and then retrieved. If you use all columns as the primary key, you may benefit from faster queries. Yet, ClickHouse performance doesn’t only depend on reading data, but on writing it, too. When the primary key contains many columns, the whole cluster slows down when data is written to it. The optimal size of the primary key in ClickHouse is two or three columns, so you can run faster queries but not slow down data inserts. When choosing the columns, think of the requests that will be made and go for columns that will often be selected in filters. Tip 5: Avoid Small Inserts When you insert data in ClickHouse, it first saves a part with this data to a disk. It then sorts this data, merges it, and inserts it into the right place in the database in the background. If you insert small chunks of data very often, ClickHouse will create a part for every small insert. It will slow down the whole cluster and you may get the “Too many parts” error. To insert data efficiently, add data in big chunks and avoid sending more than one insert statement per second. ClickHouse can insert a lot of data at a high pace — even 100K rows per second is okay — but it should be one bulk insert instead of multiple smaller ones. If your data comes in small portions, consider using an external system such as Managed Kafka for making batches of data. ClickHouse is well integrated with Kafka and can efficiently consume data from it. Tip 6: Think of How You Will Get Rid of Duplicate Data Primary keys in ClickHouse don’t ensure that data is unique. Unlike other databases, if you insert duplicate data in ClickHouse, it will be added as is. Thus, the best option would be to ensure that the data is unique before inserting it. You can do it, for example, in a stream processing application, like Apache Kafka. If it’s not possible, there are ways to deal with it when you run queries. One option is to use `argMax` to select only the last version of the duplicate row. You can also use the ReplacingMergeTree engine that removes duplicate entries by design. Finally, you can run `OPTIMIZE TABLE ... FINAL` to merge data parts, but that’s a resource-demanding operation, and you should only run it when you know it won’t affect the cluster performance. Tip 7: Don’t Create an Index for Every Column Just like with primary keys, you may want to use multiple indexes to improve performance. This may be the case when you query data with the filters that match an index, but overall it won’t help you make queries faster. At the same time, you’ll certainly experience the downsides of this strategy. Multiple indexes significantly slow down data inserts because ClickHouse will need to both write the data in the correct place and then update indexes. When you want to create indexes in a production cluster, select the columns that correlate with the primary key.

By Vladimir Ivoninskii
The Benefits of Using RTK Query: A Scalable and Efficient Solution
The Benefits of Using RTK Query: A Scalable and Efficient Solution

As developers, we're constantly seeking ways to streamline our workflows and enhance the performance of our applications. One tool that has gained significant traction in the React ecosystem is Redux Toolkit Query (RTK Query). This library, built on top of Redux Toolkit, provides a solution for managing asynchronous data fetching and caching. In this article, we'll explore the key benefits of using RTK Query. The Benefits of Using RTK Query: A Scalable and Efficient Solution 1. Simplicity and Ease of Use One of the most compelling advantages of RTK Query is its simplicity. This is how one would easily define endpoints for various operations, such as querying data, and creating, updating, and deleting resources. The injectEndpoints method allows you to define these endpoints in a concise and declarative manner, reducing boilerplate code and improving readability. TypeScript booksApi.injectEndpoints({ endpoints: builder => ({ getBooks: builder.query<IBook[], void | string[]>({ // ... }), createBundle: builder.mutation<any, void>({ // ... }), addBook: builder.mutation<string, AddBookArgs>({ // ... }), // ... }), }); 2. Automatic Caching and Invalidation One of the features of RTK Query is its built-in caching mechanism. The library automatically caches the data fetched from your endpoints, ensuring that subsequent requests for the same data are served from the cache, reducing network overhead and improving performance. These examples demonstrate how RTK Query handles cache invalidation using the invalidatesTags option. TypeScript createBundle: builder.mutation<any, void>({ invalidatesTags: [BooksTag], // ... }), addBook: builder.mutation<string, AddBookArgs>({ invalidatesTags: [BooksTag], // ... }), By specifying the BooksTag, RTK Query knows which cache entries to invalidate when a mutation (e.g., createBundle or addBook) is performed, ensuring that the cache stays up-to-date and consistent with the server data. 3. Scalability and Maintainability As your application grows in complexity, managing asynchronous data fetching and caching can become increasingly challenging. RTK Query's modular approach and separation of concerns make it easier to scale and maintain your codebase. Each endpoint is defined independently, allowing you to easily add, modify, or remove endpoints as needed without affecting the rest of your application. TypeScript endpoints: builder => ({ getBooks: builder.query<IBook[], void | string[]>({ // ... }), createBundle: builder.mutation<any, void>({ // ... }), // ... }) This modular structure promotes code reusability and makes it easier to reason about the different parts of your application, leading to better maintainability and collaboration within your team. 4. Efficient Data Fetching and Normalization RTK Query provides built-in support for efficient data fetching and normalization. The queryFn shows how you can fetch data from multiple sources and normalize the data using the toSimpleBooks function. However, the current implementation can be optimized to reduce code duplication and improve readability. Here's an optimized version of the code: TypeScript async queryFn(collections) { try { const [snapshot, snapshot2] = await Promise.all( collections.map(fetchCachedCollection) ]); const success = await getBooksBundle(); const books = success ? toSimpleBooks([...snapshot.docs, ...snapshot2.docs]) : []; return { data: books }; } catch (error) { return { error }; } } In this optimized version, we're using Promise.all to fetch the two collections (latest-books-1-query and latest-books-2-query) concurrently. This approach ensures that we don't have to wait for one collection to finish fetching before starting the other, potentially reducing the overall fetching time. Additionally, we've moved the getBooksBundle call inside the try block, ensuring that it's executed only if the collections are fetched successfully. This change helps maintain a clear separation of concerns and makes the code easier to reason about. By leveraging RTK Query's efficient data fetching capabilities and employing best practices like Promise.all, you can ensure that your application fetches and normalizes data in an optimized and efficient manner, leading to improved performance and a better user experience. 5. Ease of Use With Exposed Hooks One of the standout features of RTK Query is the ease of use it provides through its exposed hooks. Finally, I like to export the available generated typed hooks so you can use them (i.e, useGetBooksQuery, useCreateBundleMutation, etc.) to interact with the defined endpoints within your React components. These hooks abstract away the complexities of managing asynchronous data fetching and caching, allowing you to focus on building your application's logic. TypeScript export const { useGetBooksQuery, useLazyGetBooksQuery, useCreateBundleMutation, useAddBookMutation, useDeleteBookMutation, useUpdateBookMutation, } = booksApi; By leveraging these hooks, you can fetch data, trigger mutations, and handle loading and error states, all while benefiting from the caching and invalidation mechanisms provided by RTK Query. Conclusion By adopting RTK Query, you gain access to a solution for managing asynchronous data fetching and caching, while experiencing the simplicity, scalability, and ease of use provided by its exposed hooks. Whether you're building a small application or a large-scale project, RTK Query can help you streamline your development process and deliver high-performance, responsive applications. The code within this post is taken from a live app in production, ReadM, a Real-time AI for Reading Fluency Assessments & Insights platform.

By Oren Farhi
Exploring WebAssembly for Cloud-Native Development
Exploring WebAssembly for Cloud-Native Development

I’m a senior solution architect and polyglot programmer interested in the evolution of programming languages and their impact on application development. Around three years ago, I encountered WebAssembly (Wasm) through the .NET Blazor project. This technology caught my attention because it can execute applications at near-native speed across different programming languages. This was especially exciting to me as a polyglot programmer since my programming expertise ranges across multiple programming languages including .NET, PHP, Node.js, Rust, and Go. Most of the work I do is building cloud-native enterprise applications, so I have been particularly interested in advancements that broaden Wasm’s applicability in cloud-native development. WebAssembly 2.0 was a significant leap forward, improving performance and flexibility while streamlining integration with web and cloud infrastructures to make Wasm an even more powerful tool for developers to build versatile and dynamic cloud-native applications. I aim to share the knowledge and understanding I've gained, providing an overview of Wasm’s capabilities and its potential impact on the cloud-native development landscape. Polyglot Programming and the Component Model My initial attraction to WebAssembly stemmed from its capability to enhance browser functionalities for graphic-intensive and gaming applications, breaking free from the limitations of traditional web development. It also allows developers to employ languages like C++ or Rust to perform high-efficiency computations and animations, offering near-native performance within the browser environment. Wasm’s polyglot programming capability and component model are two of its flagship capabilities. The idea of leveraging the strengths of various programming languages within a unified application environment seemed like the next leap in software development. Wasm offers the potential to leverage the unique strengths of various programming languages within a single application environment, promoting a more efficient and versatile development process. For instance, developers could leverage Rust's speed for performance-critical components and .NET's comprehensive library support for business logic to optimize both development efficiency and application performance. This led me to Spin, an open-source tool for the creation and deployment of Wasm applications in cloud environments. To test Wasm’s polyglot programming capabilities, I experimented with the plugins and middleware models. I divided the application business logic into one component, and the other component with the Spin component supported the host capabilities (I/O, random, socket, etc.) to work with the host. Finally, I composed with http-auth-middleware, an existing component model from Spin for OAuth 2.0, and wrote more components for logging, rate limit, etc. All of them were composed together into one app and run on the host world (Component Model). Cloud-Native Coffeeshop App The first app I wrote using WebAssembly was an event-driven microservices coffeeshop app written in Golang and deployed using Nomad, Consul Connect, Vault, and Terraform (you can see it on my GitHub). I was curious about how it would work with Kubernetes, and then Dapr. I expanded it and wrote several use cases with Dapr such as entire apps with Spin, polyglot apps (Spin and other container apps with Docker), Spin apps with Dapr, and others. What I like about it is the speed of start-up time (it’s very quick to get up and running), and the size of the app – it looks like a tiny but powerful app. The WebAssembly ecosystem has matured a lot in the past year as it relates to enterprise projects. For the types of cloud-native projects I’d like to pursue, it would benefit from a more developed support system for stateful applications, as well as an integrated messaging system between components. I would love to see more capabilities that my enterprise customers need such as gRPC or other communication protocols (Spin currently only supports HTTP), data processing and transformation like data pipelines, a multi-threading mechanism, CQRS, polyglot programming language aggregations (internal modular monolith style or external microservices style), and content negotiation (XML, JSON, Plain-text). We also need real-world examples demonstrating Wasm’s capabilities to tackle enterprise-level challenges, fostering a better understanding and wider technology adoption. We can see how well ZEISS does from their presentation at KubeCon in Paris last month. I would like to see more and more companies like them involved in this game, then, from the developer perspective, we will benefit a lot. Not only can we easily develop WebAssembly apps, but many enterprise scenarios shall also be addressed, and we will work together to make WebAssembly more handy and effective. The WebAssembly Community Sharing my journey with the WebAssembly community has been a rewarding part of my exploration, especially with the Spin community who have been so helpful in sharing best practices and new ideas. Through tutorials and presentations at community events, I've aimed to contribute to the collective understanding of WebAssembly and cloud-native development, and I hope to see more people sharing their experiences. I will continue creating tutorials and educational content, as well as diving into new projects using WebAssembly to inspire and educate others about its potential. I would encourage anyone getting started to get involved in the Wasm community of your choice to accelerate your journey. WebAssembly’s Cloud-Native Future I feel positive about the potential for WebAssembly to change how we do application development, particularly in the cloud-native space. I’d like to explore how Wasm could underpin the development of hybrid cloud platforms and domain-specific applications. One particularly exciting prospect is the potential for building an e-commerce platform based on WebAssembly, leveraging its cross-platform capabilities and performance benefits to offer a superior user experience. The plugin model existed for a long time in the e-commerce world (see what Shopify did), and with WebAssembly’s component model, we can build the application with polyglot programming languages such as Rust, Go, TypeScript, .NET, Java, PHP, etc. WebAssembly 2.0 supports the development of more complex and interactive web applications, opening the door for new use cases such as serverless stateless functions, data transformation, and the full-pledge of web API functionalities, moving into edge devices (some embedded components). New advancements like WASI 3.0 with asynchronous components are bridging the gaps. I eagerly anticipate the further impact of WebAssembly on our approaches to building and deploying applications. We’re just getting started.

By Thang Chung
Operation and Network Administration Management of Telecom 5G Network Functions Using Openshift Kubernetes Tools
Operation and Network Administration Management of Telecom 5G Network Functions Using Openshift Kubernetes Tools

The world of Telecom is evolving at a rapid pace, and it is not just important, but crucial for operators to stay ahead of the game. As 5G technology becomes the norm, it is not just essential, but a strategic imperative to transition seamlessly from 4G technology (which operates on OpenStack cloud) to 5G technology (which uses Kubernetes). In the current scenario, operators invest in multiple vendor-specific monitoring tools, leading to higher costs and less efficient operations. However, with the upcoming 5G world, operators can adopt a unified monitoring and alert system for all their products. This single system, with its ability to monitor network equipment, customer devices, and service platforms, offers a reassuringly holistic view of the entire system, thereby reducing complexity and enhancing efficiency. By adopting a Prometheus-based monitoring and alert system, operators can streamline operations, reduce costs, and enhance customer experience. With a single monitoring system, operators can monitor their entire 5G system seamlessly, ensuring optimal performance and avoiding disruptions. This practical solution eliminates the need for a complete overhaul and offers a cost-effective transition. Let's dive deep. Prometheus, Grafana, and Alert Manager Prometheus is a tool for monitoring and alerting systems, utilizing a pull-based monitoring system. It scrapes, collects, and stores Key Performance Indicators (KPI) with labels and timestamps, enabling it to collect metrics from targets, which are the Network Functions' namespaces in the 5G telecom world. Grafana is a dynamic web application that offers a wide range of functionalities. It visualizes data, allowing the building of charts, graphs, and dashboards that the 5G Telecom operator wants to visualize. Its primary feature is the display of multiple graphing and dashboarding support modes using GUI (Graphical user interface). Grafana can seamlessly integrate data collected by Prometheus, making it an indispensable tool for telecom operators. It is a powerful web application that supports the integration of different data sources into one dashboard, enabling continuous monitoring. This versatility improves response rates by alerting the telecom operator's team when an incident emerges, ensuring a minimum 5G network function downtime. The Alert Manager is a crucial component that manages alerts from the Prometheus server via alerting rules. It manages the received alerts, including silencing and inhibiting them and sending out notifications via email or chat. The Alert Manager also removes duplications, grouping, and routing them to the centralized webhook receiver, making it a must-have tool for any telecom operator. Architectural Diagram Prometheus Components of Prometheus (Specific to a 5G Telecom Operator) Core component: Prometheus server scrapes HTTP endpoints and stores data (time series).The Prometheus server, a crucial component in the 5G telecom world, collects metrics from the Prometheus targets. In our context, these targets are the Kubernetes cluster that houses the 5G network functions.Time series database (TSDB): Prometheus stores telecom Metrics as time series data.HTTP Server: API to query data stored in TSDB; The Grafana dashboard can query this data for visualization.Telecom operator-specific libraries (5G) for instrumenting application code.Push gateway (scrape target for short-lived jobs)Service Discovery: In the world of 5G, network function pods are constantly being added or deleted by Telecom operators to scale up or down. Prometheus's adaptable service discovery component monitors the ever-changing list of pods. The Prometheus Web UI, accessible through port 9090, is a data visualization tool. It allows users to view and analyze Prometheus data in a user-friendly and interactive manner, enhancing the monitoring capabilities of the 5G telecom operators.The Alert Manager, a key component of Prometheus, is responsible for handling alerts. It is designed to notify users if something goes wrong, triggering notifications when certain conditions are met. When alerting triggers are met, Prometheus alerts the Alert Manager, which sends alerts through various channels such as email or messenger, ensuring timely and effective communication of critical issues. Grafana for dashboard visualization (actual graphs) With Prometheus's robust components, your Telecom operator's 5G network functions are monitored with diligence, ensuring reliable resource utilization, tracking performance, detection of errors in availability, and more. Prometheus can provide you with the necessary tools to keep your network running smoothly and efficiently. Prometheus Features The multi-dimensional data model identified by metric details uses PromQL (Prometheus Querying Language) as the query language and the HTTP Pull model.Telecom operators can now discover 5G network functions with service discovery and static configuration. The multiple modes of dashboard and GUI support provide a comprehensive and customizable experience for users. Prometheus Remote Write to Central Prometheus from Network Functions 5G Operators will have multiple network functions from various vendors, such as SMF (Session Management Function), UPF (User Plane Function), AMF (Access and Mobility Management Function), PCF (Policy Control Function), and UDM (Unified Data Management). Using multiple Prometheus/Grafana dashboards for each network function can lead to a complex and inefficient 5G network operator monitoring process. To address this, it is highly recommended that all data/metrics from individual Prometheus be consolidated into a single Central Prometheus, simplifying the monitoring process and enhancing efficiency. The 5G network operator can now confidently monitor all the data at the Central Prometheus's centralized location. This user-friendly interface provides a comprehensive view of the network's performance, empowering the operator with the necessary tools for efficient monitoring. Grafana Grafana Features Panels: This powerful feature empowers operators to visualize Telecom 5G data in many ways, including histograms, graphs, maps, and KPIs. It offers a versatile and adaptable interface for data representation, enhancing the efficiency and effectiveness of your data analysis.Plugins: This feature efficiently renders Telecom 5G data in real-time on a user-friendly API (Application Programming Interface), ensuring operators always have the most accurate and up-to-date data at their fingertips. It also enables operators to create data source plugins and retrieve metrics from any API.Transformations: This feature allows you to flexibly adapt, summarize, combine, and perform KPI metrics query/calculations across 5G network functions data sources, providing the tools to effectively manipulate and analyze your data.Annotations: Rich events from different Telecom 5G network functions data sources are used to annotate metrics-based graphs.Panel editor: Reliable and consistent graphical user interface for configuring and customizing 5G telecom metrics panels Grafana Sample Dashboard GUI for 5G Alert Manager Alert Manager Components The Ingester swiftly ingests all alerts, while the Grouper groups them into categories. The De-duplicator prevents repetitive alerts, ensuring you're not bombarded with notifications. The Silencer is there to mute alerts based on a label, and the Throttler regulates the frequency of alerts. Finally, the Notifier will ensure that third parties are notified promptly. Alert Manager Functionalities Grouping: Grouping categorizes similar alerts into a single notification system. This is helpful during more extensive outages when many 5G network functions fail simultaneously and when all the alerts need to fire simultaneously.The telecom operator will expect only to get a single page while still being able to visualize the exact service instances affected.Inhibition: Inhibition suppresses the notification for specific low-priority alerts if certain major/critical alerts are already firing.For example, when a critical alert fires, indicating that an entire 5G SMF (Session Management Function) cluster is not reachable, AlertManager can mute all other minor/warning alerts concerning this cluster.Silences: Silences are simply mute alerts for a given time. Incoming alerts are checked to match the regular expression matches of an active silence. If they match, no notifications will be sent out for that alert.High availability: Telecom operators will not load balance traffic between Prometheus and all its Alert Managers; instead, they will point Prometheus to a list of all Alert Managers. Dashboard Visualization Grafana dashboard visualizes the Alert Manager webhook traffic notifications as shown below: Configuration YAMLs (Yet Another Markup Language) Telecom Operators can install and run Prometheus using the configuration below: YAML prometheus: enabled: true route: enabled: {} nameOverride: Prometheus tls: enabled: true certificatesSecret: backstage-prometheus-certs certFilename: tls.crt certKeyFilename: tls.key volumePermissions: enabled: true initdbScriptsSecret: backstage-prometheus-initdb prometheusSpec: retention: 3d replicas: 2 prometheusExternalLabelName: prometheus_cluster image: repository: <5G operator image repository for Prometheus> tag: <Version example v2.39.1> sha: "" podAntiAffinity: "hard" securityContext: null resources: limits: cpu: 1 memory: 2Gi requests: cpu: 500m memory: 1Gi serviceMonitorNamespaceSelector: matchExpressions: - {key: namespace, operator: In, values: [<Network function 1 namespace>, <Network function 2 namespace>]} serviceMonitorSelectorNilUsesHelmValues: false podMonitorSelectorNilUsesHelmValues: false ruleSelectorNilUsesHelmValues: false Configuration to route scrape data segregated based on the namespace and route to Central Prometheus. Note: The below configuration can be appended to the Prometheus mentioned in the above installation YAML. YAML remoteWrite: - url: <Central Prometheus URL for namespace 1 by 5G operator> basicAuth: username: name: <secret username for namespace 1> key: username password: name: <secret password for namespace 1> key: password tlsConfig: insecureSkipVerify: true writeRelabelConfigs: - sourceLabels: - namespace regex: <namespace 1> action: keep - url: <Central Prometheus URL for namespace 2 by 5G operator> basicAuth: username: name: <secret username for namespace 2> key: username password: name: <secret password for namespace 2> key: password tlsConfig: insecureSkipVerify: true writeRelabelConfigs: - sourceLabels: - namespace regex: <namespace 2> action: keep Telecom Operators can install and run Grafana using the configuration below. YAML grafana: replicas: 2 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: "app.kubernetes.io/name" operator: In values: - Grafana topologyKey: "kubernetes.io/hostname" securityContext: false rbac: pspEnabled: false # Must be disabled due to tenant permissions namespaced: true adminPassword: admin image: repository: <artifactory>/Grafana tag: <version> sha: "" pullPolicy: IfNotPresent persistence: enabled: false initChownData: enabled: false sidecar: image: repository: <artifactory>/k8s-sidecar tag: <version> sha: "" imagePullPolicy: IfNotPresent resources: limits: cpu: 100m memory: 100Mi requests: cpu: 50m memory: 50Mi dashboards: enabled: true label: grafana_dashboard labelValue: "Vendor name" datasources: enabled: true defaultDatasourceEnabled: false additionalDataSources: - name: Prometheus type: Prometheus url: http://<prometheus-operated>:9090 access: proxy isDefault: true jsonData: timeInterval: 30s resources: limits: cpu: 400m memory: 512Mi requests: cpu: 50m memory: 206Mi extraContainers: - name: oauth-proxy image: <artifactory>/origin-oauth-proxy:<version> imagePullPolicy: IfNotPresent ports: - name: proxy-web containerPort: 4181 args: - --https-address=:4181 - --provider=openshift # Service account name here must be "<Helm Release name>-grafana" - --openshift-service-account=monitoring-grafana - --upstream=http://localhost:3000 - --tls-cert=/etc/tls/private/tls.crt - --tls-key=/etc/tls/private/tls.key - --cookie-secret=SECRET - --pass-basic-auth=false resources: limits: cpu: 100m memory: 256Mi requests: cpu: 50m memory: 128Mi volumeMounts: - mountPath: /etc/tls/private name: grafana-tls extraContainerVolumes: - name: grafana-tls secret: secretName: grafana-tls serviceAccount: annotations: "serviceaccounts.openshift.io/oauth-redirecturi.first": https://[SPK exposed IP for Grafana] service: targetPort: 4181 annotations: service.alpha.openshift.io/serving-cert-secret-name: <secret> Telecom Operators can install and run Alert Manager using the configuration below. YAML alertmanager: enabled: true alertmanagerSpec: image: repository: prometheus/alertmanager tag: <version> replicas: 2 podAntiAffinity: hard securityContext: null resources: requests: cpu: 25m memory: 200Mi limits: cpu: 100m memory: 400Mi containers: - name: config-reloader resources: requests: cpu: 10m memory: 10Mi limits: cpu: 25m memory: 50Mi Configuration to route Prometheus Alert Manager data to the Operator's centralized webhook receiver. Note: The below configuration can be appended to the Alert Manager mentioned in the above installation YAML. YAML config: global: resolve_timeout: 5m route: group_by: ['alertname'] group_wait: 30s group_interval: 5m repeat_interval: 12h receiver: 'null' routes: - receiver: '<Network function 1>' group_wait: 10s group_interval: 10s group_by: ['alertname','oid','action','time','geid','ip'] matchers: - namespace="<namespace 1>" - receiver: '<Network function 2>' group_wait: 10s group_interval: 10s group_by: ['alertname','oid','action','time','geid','ip'] matchers: - namespace="<namespace 2>" Conclusion The open-source OAM (Operation and Maintenance) tools Prometheus, Grafana, and Alert Manager can benefit 5G Telecom operators. Prometheus periodically captures all the status of monitored 5G Telecom network functions through the HTTP protocol, and any component can be connected to the monitoring as long as the 5G Telecom operator provides the corresponding HTTP interface. Prometheus and Grafana Agent gives the 5G Telecom operator control over the metrics the operator wants to report; once the data is in Grafana, it can be stored in a Grafana database as extra data redundancy. In conclusion, Prometheus allows 5G Telecom operators to improve their operations and offer better customer service. Adopting a unified monitoring and alert system like Prometheus is one way to achieve this.

By BINU SUDHAKARAN PILLAI
How To Build Local LLM Apps With Ollama and SingleStore
How To Build Local LLM Apps With Ollama and SingleStore

In an era of heightened data privacy concerns, the development of local Large Language Model (LLM) applications provides an alternative to cloud-based solutions. Ollama offers one solution, enabling LLMs to be downloaded and used locally. In this article, we'll explore how to use Ollama with LangChain and SingleStore using a Jupyter Notebook. The notebook file used in this article is available on GitHub. Introduction We'll use a Virtual Machine running Ubuntu 22.04.2 as our test environment. An alternative would be to use venv. Create a SingleStoreDB Cloud Account A previous article showed the steps required to create a free SingleStore Cloud account. We'll use Ollama Demo Group as our Workspace Group Name and ollama-demo as our Workspace Name. We’ll make a note of our password and host name. For this article, we'll temporarily allow access from anywhere by configuring the firewall under Ollama Demo Group > Firewall. For production environments, firewall rules should be added to provide increased security. Create a Database In our SingleStore Cloud account, let's use the SQL Editor to create a new database. Call this ollama_demo, as follows: SQL CREATE DATABASE IF NOT EXISTS ollama_demo; Install Jupyter From the command line, we’ll install the classic Jupyter Notebook, as follows: Shell pip install notebook Install Ollama We'll install Ollama, as follows: Shell curl -fsSL https://ollama.com/install.sh | sh Environment Variable Using the password and host information we saved earlier, we’ll create an environment variable to point to our SingleStore instance, as follows: Shell export SINGLESTOREDB_URL="admin:<password>@<host>:3306/ollama_demo" Replace <password> and <host> with the values for your environment. Launch Jupyter We are now ready to work with Ollama and we’ll launch Jupyter: Shell jupyter notebook Fill Out the Notebook First, some packages: Shell !pip install langchain ollama --quiet --no-warn-script-location Next, we’ll import some libraries: Python import ollama from langchain_community.vectorstores import SingleStoreDB from langchain_community.vectorstores.utils import DistanceStrategy from langchain_core.documents import Document from langchain_community.embeddings import OllamaEmbeddings We'll create embeddings using all-minilm (45 MB at the time of writing): Python ollama.pull("all-minilm") Example output: Plain Text {'status': 'success'} For our LLM we'll use llama2 (3.8 GB at the time of writing): Python ollama.pull("llama2") Example output: Plain Text {'status': 'success'} Next, we’ll use the example text from the Ollama website: Python documents = [ "Llamas are members of the camelid family meaning they're pretty closely related to vicuñas and camels", "Llamas were first domesticated and used as pack animals 4,000 to 5,000 years ago in the Peruvian highlands", "Llamas can grow as much as 6 feet tall though the average llama between 5 feet 6 inches and 5 feet 9 inches tall", "Llamas weigh between 280 and 450 pounds and can carry 25 to 30 percent of their body weight", "Llamas are vegetarians and have very efficient digestive systems", "Llamas live to be about 20 years old, though some only live for 15 years and others live to be 30 years old" ] embeddings = OllamaEmbeddings( model = "all-minilm", ) dimensions = len(embeddings.embed_query(documents[0])) docs = [Document(text) for text in documents] We’ll specify all-minilm for the embeddings, determine the number of dimensions returned for the first document, and convert the documents to the format required by SingleStore. Next, we’ll use LangChain: Python docsearch = SingleStoreDB.from_documents( docs, embeddings, table_name = "langchain_docs", distance_strategy = DistanceStrategy.EUCLIDEAN_DISTANCE, use_vector_index = True, vector_size = dimensions ) In addition to the documents and embeddings, we’ll provide the name of the table we want to use for storage, the distance strategy, that we want to use a vector index, and the vector size using the dimensions we previously determined. These and other options are explained in further detail in the LangChain documentation. Using the SQL Editor in SingleStore Cloud, let’s check the structure of the table created by LangChain: SQL USE ollama_demo; DESCRIBE langchain_docs; Example output: Plain Text +----------+------------------+------+------+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+------------------+------+------+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | content | longtext | YES | | NULL | | | vector | vector(384, F32) | NO | MUL | NULL | | | metadata | JSON | YES | | NULL | | +----------+------------------+------+------+---------+----------------+ We can see that a vector column with 384 dimensions was created for storing the embeddings. Let’s also quickly check the stored data: SQL USE ollama_demo; SELECT SUBSTRING(content, 1, 30) AS content, SUBSTRING(vector, 1, 30) AS vector FROM langchain_docs; Example output: Plain Text +--------------------------------+--------------------------------+ | content | vector | +--------------------------------+--------------------------------+ | Llamas weigh between 280 and 4 | [0.235754818,0.242168128,-0.26 | | Llamas were first domesticated | [0.153105229,0.219774529,-0.20 | | Llamas are vegetarians and hav | [0.285528302,0.10461951,-0.313 | | Llamas are members of the came | [-0.0174482632,0.173883006,-0. | | Llamas can grow as much as 6 f | [-0.0232818555,0.122274697,-0. | | Llamas live to be about 20 yea | [0.0260244086,0.212311044,0.03 | +--------------------------------+--------------------------------+ Finally, let’s check the vector index: SQL USE ollama_demo; SHOW INDEX FROM langchain_docs; Example output: Plain Text +----------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------------+---------+---------------+---------------------------------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Index_options | +----------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------------+---------+---------------+---------------------------------------+ | langchain_docs | 0 | PRIMARY | 1 | id | NULL | NULL | NULL | NULL | | COLUMNSTORE HASH | | | | | langchain_docs | 1 | vector | 1 | vector | NULL | NULL | NULL | NULL | | VECTOR | | | {"metric_type": "EUCLIDEAN_DISTANCE"} | | langchain_docs | 1 | __SHARDKEY | 1 | id | NULL | NULL | NULL | NULL | | METADATA_ONLY | | | | +----------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------------+---------+---------------+---------------------------------------+ We’ll now ask a question, as follows: Python prompt = "What animals are llamas related to?" docs = docsearch.similarity_search(prompt) data = docs[0].page_content print(data) Example output: Plain Text Llamas are members of the camelid family meaning they're pretty closely related to vicuñas and camels Next, we’ll use the LLM, as follows: Python output = ollama.generate( model = "llama2", prompt = f"Using this data: {data}. Respond to this prompt: {prompt}" ) print(output["response"]) Example output: Plain Text Llamas are members of the camelid family, which means they are closely related to other animals such as: 1. Vicuñas: Vicuñas are small, wild relatives of llamas and alpacas. They are native to South America and are known for their soft, woolly coats. 2. Camels: Camels are also members of the camelid family and are known for their distinctive humps on their backs. There are two species of camel: the dromedary and the Bactrian. 3. Alpacas: Alpacas are domesticated animals that are closely related to llamas and vicuñas. They are native to South America and are known for their soft, luxurious fur. So, in summary, llamas are related to vicuñas, camels, and alpacas. Summary In this article, we’ve seen that we can connect to SingleStore, store the documents and embeddings, ask questions about the data in the database, and use the power of LLMs locally through Ollama.

By Akmal Chaudhri DZone Core CORE
CORS Anywhere on Pure NGINX Config
CORS Anywhere on Pure NGINX Config

Cross-Origin Resource Sharing (CORS) often becomes a stumbling block for developers attempting to interact with APIs hosted on different domains. The challenge intensifies when direct server configuration isn't an option, pushing developers towards alternative solutions like the widely-used cors-anywhere. However, less known is the capability of NGINX's proxy_pass directive to handle not only local domains and upstreams but also external sources, for example: This is how the idea was born to write a universal (with some reservations) NIGNX config that supports any given domain. Understanding the Basics and Setup CORS is a security feature that restricts web applications from making requests to a different domain than the one that served the web application itself. This is a crucial security measure to prevent malicious websites from accessing sensitive data. However, when legitimate cross-domain requests are necessary, properly configuring CORS is essential. The NGINX proxy server offers a powerful solution to this dilemma. By utilizing NGINX's flexible configuration system, developers can create a proxy that handles CORS preflight requests and manipulates headers to ensure compliance with CORS policies. Here's how: Variable Declaration and Manipulation With the map directive, NGINX allows the declaration of new variables based on existing global ones, incorporating regular expression support for dynamic processing. For instance, extracting a specific path from a URL can be achieved, allowing for precise control over request handling. Thus, when requesting http://example.com/api, the $my_request_path variable will contain api. Header Management NGINX facilitates the addition of custom headers to responses via add_header and to proxied requests through proxy_set_header. Simultaneously, proxy_hide_header can be used to conceal headers received from the proxied server, ensuring only the necessary information is passed back to the client. We now have an X-Request-Path header with api. Conditional Processing Utilizing the if directive, NGINX can perform actions based on specific conditions, such as returning a predetermined response code for OPTIONS method requests, streamlining the handling of CORS preflight checks. Putting It All Together First, let’s declare $proxy_uri that we will extract from $request_uri: In short, it works like this: when requesting http://example.com/example.com, the $proxy_uri variable will contain https://example.com. From the resulting $proxy_uri, extract the part that will match the Origin header: For the Forwarded header, we need to process 2 variables at once: The processed X-Forwarded-For header is already built into NGINX. Now we can move on to declaring our proxy server: We get a minimally working proxy server, which can process the CORS Preflight Request and add the appropriate headers. Enhancing Security and Performance Beyond basic setup, further refinements can improve security and performance: Hiding CORS Headers When NGINX handles CORS internally, it's beneficial to hide these headers from client responses to prevent exposure of server internals. Rate Limit Bypassing It would also be nice to pass the client’s IP to somehow bypass the rate limit, which can occur if several users access the same resource. Disabling Caching And finally, for dynamic content or sensitive information, disabling caching is a best practice, ensuring data freshness and privacy. Conclusion This guide not only demystifies the process of configuring NGINX to handle CORS requests but also equips developers with the knowledge to create a robust, flexible proxy server capable of supporting diverse application needs. Through careful configuration and understanding of both CORS policies and NGINX's capabilities, developers can overcome cross-origin restrictions, enhance application performance, and ensure data security. This advanced understanding and application of NGINX not only solves a common web development hurdle but also showcases the depth of skill and innovation possible when navigating web security and resource-sharing challenges.

By Alexey Shepelev DZone Core CORE
API Appliance for Extreme Agility and Simplicity
API Appliance for Extreme Agility and Simplicity

Just as you can plug in a toaster, and add bread... You can plug this API Appliance into your database, and add rules and Python. Automation can provide: Remarkable agility and simplicityWith all the flexibility of a framework Using conventional frameworks, creating a modern, API-based web app is a formidable undertaking. It might require several weeks and extensive knowledge of a framework. In this article, we'll use API Logic Server (open source, available here) to create it in minutes, instead of weeks or months. And, we'll show how it can be done with virtually zero knowledge of frameworks, or even Python. We'll even show how to add message-based integration. 1. Plug It Into Your Database Here's how you plug the ApiLogicServer appliance into your database: $ ApiLogicServer create-and-run --project-name=sample_ai --db-url=sqlite:///sample_ai.sqlite No database? Create one with AI, as described in the article, "AI and Rules for Agile Microservices in Minutes." It Runs: Admin App and API Instantly, you have a running system as shown on the split-screen below: A multi-page Admin App (shown on the left), supported by...A multi-table JSON:API with Swagger (shown on the right) So right out of the box, you can support: Custom client app devAd hoc application integrationAgile collaboration, based on working software Instead of weeks of complex and time-consuming framework coding, you have working software, now. Containerize API Logic Server can run as a container or a standard pip install. In either case, scripts are provided to containerize your project for deployment, e.g., to the cloud. 2. Add Rules for Logic Instant working software is great: one command instead of weeks of work, and virtually zero knowledge required. But without logic enforcement, it's little more than a cool demo. Behind the running application is a standard project. Open it with your IDE, and: Declare logic with code completion.Debug it with your debugger. Instead of conventional procedural logic, the code above is declarative. Like a spreadsheet, you declare rules for multi-table derivations and constraints. The rules handle all the database access, dependencies, and ordering. The results are quite remarkable: The 5 spreadsheet-like rules above perform the same logic as 200 lines of Python.The backend half of your system is 40X more concise. Similar rules are provided for granting row-level access, based on user roles. 3. Add Python for Flexibility Automation and rules provide remarkable agility with very little in-depth knowledge required. However, automation always has its limits: you need flexibility to deliver a complete result. For flexibility, the appliance enables you to use Python and popular packages to complete the job. Below, we customize for pricing discounts and sending Kafka messages: Extensible Declarative Automation The screenshots above illustrate remarkable agility. This system might have taken weeks or months using conventional frameworks. But it's more than agility. The level of abstraction here is very high, bringing a level of simplicity that empowers you to create microservices - even if you are new to Python or frameworks such as Flask and SQLAlchemy. There are 3 key elements that deliver this speed and simplicity: Microservice automation: Instead of slow and complex framework coding, just plug into your database for an instant API and Admin App.Logic automation with declarative rules: Instead of tedious code that describes how logic operates, rules express what you want to accomplish.Extensibility: Finish the remaining elements with your IDE, Python, and standard packages such as Flask and SQLAlchemy. This automation appliance can provide remarkable benefits, empowering more people, to do more.

By Val Huber DZone Core CORE
Leveraging Feature Flags With IBM Cloud App Configuration in React Applications
Leveraging Feature Flags With IBM Cloud App Configuration in React Applications

In modern application development, delivering personalized and controlled user experiences is paramount. This necessitates the ability to toggle features dynamically, enabling developers to adapt their applications in response to changing user needs and preferences. Feature flags, also known as feature toggles, have emerged as a critical tool in achieving this flexibility. These flags empower developers to activate or deactivate specific functionalities based on various criteria such as user access, geographic location, or user behavior. React, a popular JavaScript framework known for its component-based architecture, is widely adopted in building user interfaces. Given its modular nature, React applications are particularly well-suited for integrating feature flags seamlessly. In this guide, we'll explore how to integrate feature flags into your React applications using IBM App Configuration, a robust platform designed to manage application features and configurations. By leveraging feature flags and IBM App Configuration, developers can unlock enhanced flexibility and control in their development process, ultimately delivering tailored user experiences with ease. IBM App Configuration can be integrated with any framework be it React, Angular, Java, Go, etc. React is a popular JavaScript framework that uses a component-based architecture, allowing developers to build reusable and modular UI components. This makes it easier to manage complex user interfaces by breaking them down into smaller, self-contained units. Adding feature flags to React components will make it easier for us to handle the components. Integrating With IBM App Configuration IBM App Configuration provides a comprehensive platform for managing feature flags, environments, collections, segments, and more. Before delving into the tutorial, it's important to understand why integrating your React application with IBM App Configuration is necessary and what benefits it offers. By integrating with IBM App Configuration, developers gain the ability to dynamically toggle features on and off within their applications. This capability is crucial for modern application development, as it allows developers to deliver controlled and personalized user experiences. With feature flags, developers can activate or deactivate specific functionalities based on factors such as user access, geographic location, or user preferences. This not only enhances user experiences but also provides developers with greater flexibility and control over feature deployments. Additionally, IBM App Configuration offers segments for targeted rollouts, enabling developers to gradually release features to specific groups of users. Overall, integrating with IBM App Configuration empowers developers to adapt their applications' behavior in real time, improving agility, and enhancing user satisfaction. To begin integrating your React application with App Configuration, follow these steps: 1. Create an Instance Start by creating an instance of IBM App Configuration on cloud.ibm.com. Within the instance, create an environment, such as Dev, to manage your configurations. Now create a collection. Creating collections comes in handy when there are multiple feature flags created for various projects. Each project can have a collection in the same App Configuration instance and you can tag these feature flags to the collection to which they belong. 2. Generate Credentials Access the service credentials section and generate new credentials. These credentials will be required to authenticate your React application with App Configuration. 3. Install SDK In your React application, install the IBM App Configuration React SDK using npm: CSS npm i ibm-appconfiguration-react-client-sdk 4. Configure Provider In your index.js or App.js, wrap your application component with AppConfigProvider to enable AppConfig within your React app. The Provider must be wrapped at the main level of the application, to ensure the entire application has access. The AppConfigProvider requires various parameters as shown in the screenshot below. All of these values can be found in the credentials created. 5. Access Feature Flags Now, within your App Configuration instance, create feature flags to control specific functionalities. Copy the feature flag ID for further integration into your code. Integrating Feature Flags Into React Components Once you've set up the AppConfig in your React application, you can seamlessly integrate feature flags into your components. Enable Components Dynamically Use the feature flag ID copied from the App Configuration instance to toggle specific components based on the flag's status. This allows you to enable or disable features dynamically without redeploying your application. Utilizing Segments for Targeted Rollouts IBM App Configuration offers segments to target specific groups of users, enabling personalized experiences and controlled rollouts. Here's how to leverage segments effectively: Define Segments Create segments based on user properties, behaviors, or other criteria to target specific user groups. Rollout Percentage Adjust the rollout percentage to control the percentage of users who receive the feature within a targeted segment. This enables gradual rollouts or A/B testing scenarios. Example If the rollout percentage is set to 100% and a particular segment is targeted, then the feature is rolled out to all the users in that particular segment.If the rollout percentage is set between 1% to 99% and the rollout percentage is 60%, for example, and a particular segment is targeted, then the feature is rolled out to randomly 60% of the users in that particular segment.If the rollout percentage is set to 0% and a particular segment is targeted, then the feature is rolled out to none of the users in that particular segment. Conclusion Integrating feature flags with IBM App Configuration empowers React developers to implement dynamic feature toggling and targeted rollouts seamlessly. By leveraging feature flags and segments, developers can deliver personalized user experiences while maintaining control over feature deployments. Start integrating feature flags into your React applications today to unlock enhanced flexibility and control in your development process.

By Pradeep Gopalgowda
Istio Explained: Unlocking the Power of Service Mesh in Microservices
Istio Explained: Unlocking the Power of Service Mesh in Microservices

In the dynamic landscape of microservices, managing communication and ensuring robust security and observability becomes a Herculean task. This is where Istio, a revolutionary service mesh, steps in, offering an elegant solution to these challenges. This article delves deep into the essence of Istio, illustrating its pivotal role in a Kubernetes (KIND) based environment, and guides you through a Helm-based installation process, ensuring a comprehensive understanding of Istio's capabilities and its impact on microservices architecture. Introduction to Istio Istio is an open-source service mesh that provides a uniform way to secure, connect, and monitor microservices. It simplifies configuration and management, offering powerful tools to handle traffic flows between services, enforce policies, and aggregate telemetry data, all without requiring changes to microservice code. Why Istio? In a microservices ecosystem, each service may be developed in different programming languages, have different versions, and require unique communication protocols. Istio provides a layer of infrastructure that abstracts these differences, enabling services to communicate with each other seamlessly. It introduces capabilities like: Traffic management: Advanced routing, load balancing, and fault injectionSecurity: Robust ACLs, RBAC, and mutual TLS to ensure secure service-to-service communicationObservability: Detailed metrics, logs, and traces for monitoring and troubleshooting Setting Up a KIND-Based Kubernetes Cluster Before diving into Istio, let's set up a Kubernetes cluster using KIND (Kubernetes IN Docker), a tool for running local Kubernetes clusters using Docker container "nodes." KIND is particularly suited for development and testing purposes. # Install KIND curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-$(uname)-amd64 chmod +x ./kind mv ./kind /usr/local/bin/kind # Create a cluster kind create cluster --name istio-demo This code snippet installs KIND and creates a new Kubernetes cluster named istio-demo. Ensure Docker is installed and running on your machine before executing these commands. Helm-Based Installation of Istio Helm, the package manager for Kubernetes, simplifies the deployment of complex applications. We'll use Helm to install Istio on our KIND cluster. 1. Install Helm First, ensure Helm is installed on your system: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh 2. Add the Istio Helm Repository Add the Istio release repository to Helm: helm repo add istio https://istio-release.storage.googleapis.com/charts helm repo update 3. Install Istio Using Helm Now, let's install the Istio base chart, the istiod service, and the Istio Ingress Gateway: # Install the Istio base chart helm install istio-base istio/base -n istio-system --create-namespace # Install the Istiod service helm install istiod istio/istiod -n istio-system --wait # Install the Istio Ingress Gateway helm install istio-ingress istio/gateway -n istio-system This sequence of commands sets up Istio on your Kubernetes cluster, creating a powerful platform for managing your microservices. To enable the Istio injection for the target namespace, use the following command. kubectl label namespace default istio-injection=enabled Exploring Istio's Features To demonstrate Istio's powerful capabilities in a microservices environment, let's use a practical example involving a Kubernetes cluster with Istio installed, and deploy a simple weather application. This application, running in a Docker container brainupgrade/weather-py, serves weather information. We'll illustrate how Istio can be utilized for traffic management, specifically demonstrating a canary release strategy, which is a method to roll out updates gradually to a small subset of users before rolling it out to the entire infrastructure. Step 1: Deploy the Weather Application First, let's deploy the initial version of our weather application using Kubernetes. We will deploy two versions of the application to simulate a canary release. Create a Kubernetes Deployment and Service for the weather application: apiVersion: apps/v1 kind: Deployment metadata: name: weather-v1 spec: replicas: 2 selector: matchLabels: app: weather version: v1 template: metadata: labels: app: weather version: v1 spec: containers: - name: weather image: brainupgrade/weather-py:v1 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: weather-service spec: ports: - port: 80 name: http selector: app: weather Apply this configuration with kubectl apply -f <file-name>.yaml. Step 2: Enable Traffic Management With Istio Now, let's use Istio to manage traffic to our weather application. We'll start by deploying a Gateway and a VirtualService to expose our application. apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: weather-gateway spec: selector: istio: ingress servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: weather spec: hosts: - "*" gateways: - weather-gateway http: - route: - destination: host: weather-service port: number: 80 This setup routes all traffic through the Istio Ingress Gateway to our weather-service. Step 3: Implementing Canary Release Let's assume we have a new version (v2) of our weather application that we want to roll out gradually. We'll adjust our Istio VirtualService to route a small percentage of the traffic to the new version. 1. Deploy version 2 of the weather application: apiVersion: apps/v1 kind: Deployment metadata: name: weather-v2 spec: replicas: 1 selector: matchLabels: app: weather version: v2 template: metadata: labels: app: weather version: v2 spec: containers: - name: weather image: brainupgrade/weather-py:v2 ports: - containerPort: 80 2. Adjust the Istio VirtualService to split traffic between v1 and v2: apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: weather spec: hosts: - "*" gateways: - weather-gateway http: - match: - uri: prefix: "/" route: - destination: host: weather-service port: number: 80 subset: v1 weight: 90 - destination: host: weather-service port: number: 80 subset: v2 weight: 10 This configuration routes 90% of the traffic to version 1 of the application and 10% to version 2, implementing a basic canary release. Also, enable the DestinationRule as well. See the following: apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: weather-service namespace: default spec: host: weather-service subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2 This example illustrates how Istio enables sophisticated traffic management strategies like canary releases in a microservices environment. By leveraging Istio, developers can ensure that new versions of their applications are gradually and safely exposed to users, minimizing the risk of introducing issues. Istio's service mesh architecture provides a powerful toolset for managing microservices, enhancing both the reliability and flexibility of application deployments. Istio and Kubernetes Services Istio and Kubernetes Services are both crucial components in the cloud-native ecosystem, but they serve different purposes and operate at different layers of the stack. Understanding how Istio differs from Kubernetes Services is essential for architects and developers looking to build robust, scalable, and secure microservices architectures. Kubernetes Services Kubernetes Services are a fundamental part of Kubernetes, providing an abstract way to expose an application running on a set of Pods as a network service. With Kubernetes Services, you can utilize the following: Discoverability: Assign a stable IP address and DNS name to a group of Pods, making them discoverable within the cluster.Load balancing: Distribute network traffic or requests among the Pods that constitute a service, improving application scalability and availability.Abstraction: Decouple the front-end service from the back-end workloads, allowing back-end Pods to be replaced or scaled without reconfiguring the front-end clients. Kubernetes Services focuses on internal cluster communication, load balancing, and service discovery. They operate at the L4 (TCP/UDP) layer, primarily dealing with IP addresses and ports. Istio Services Istio, on the other hand, extends the capabilities of Kubernetes Services by providing a comprehensive service mesh that operates at a higher level. It is designed to manage, secure, and observe microservices interactions across different environments. Istio's features include: Advanced traffic management: Beyond simple load balancing, Istio offers fine-grained control over traffic with rich routing rules, retries, failovers, and fault injection. It operates at L7 (HTTP/HTTPS/GRPC), allowing behavior to be controlled based on HTTP headers and URLs.Security: Istio provides end-to-end security, including strong identity-based authentication and authorization between services, transparently encrypting communication with mutual TLS, without requiring changes to application code.Observability: It offers detailed insights into the behavior of the microservices, including automatic metrics, logs, and traces for all traffic within a cluster, regardless of the service language or framework.Policy enforcement: Istio allows administrators to enforce policies across the service mesh, ensuring compliance with security, auditing, and operational policies. Key Differences Scope and Layer Kubernetes Services operates at the infrastructure layer, focusing on L4 (TCP/UDP) for service discovery and load balancing. Istio operates at the application layer, providing L7 (HTTP/HTTPS/GRPC) traffic management, security, and observability features. Capabilities While Kubernetes Services provides basic load balancing and service discovery, Istio offers advanced traffic management (like canary deployments and circuit breakers), secure service-to-service communication (with mutual TLS), and detailed observability (tracing, monitoring, and logging). Implementation and Overhead Kubernetes Services are integral to Kubernetes and require no additional installation. Istio, being a service mesh, is an add-on layer that introduces additional components (like Envoy sidecar proxies) into the application pods, which can add overhead but also provide enhanced control and visibility. Kubernetes Services and Istio complement each other in the cloud-native ecosystem. Kubernetes Services provides the basic necessary functionality for service discovery and load balancing within a Kubernetes cluster. Istio extends these capabilities, adding advanced traffic management, enhanced security features, and observability into microservices communications. For applications requiring fine-grained control over traffic, secure communication, and deep observability, integrating Istio with Kubernetes offers a powerful platform for managing complex microservices architectures. Conclusion Istio stands out as a transformative force in the realm of microservices, providing a comprehensive toolkit for managing the complexities of service-to-service communication in a cloud-native environment. By leveraging Istio, developers and architects can significantly streamline their operational processes, ensuring a robust, secure, and observable microservices architecture. Incorporating Istio into your microservices strategy not only simplifies operational challenges but also paves the way for innovative service management techniques. As we continue to explore and harness the capabilities of service meshes like Istio, the future of microservices looks promising, characterized by enhanced efficiency, security, and scalability.

By Rajesh Gheware DZone Core CORE
Deno Security: Building Trustworthy Applications
Deno Security: Building Trustworthy Applications

In the world of modern web development, security is paramount. With the rise of sophisticated cyber threats, developers need robust tools and frameworks to build secure applications. Deno, a secure runtime for JavaScript and TypeScript, has emerged as a promising solution for developers looking to enhance the security of their applications. Deno was created by Ryan Dahl, the original creator of Node.js, with a focus on addressing some of the security issues present in Node.js. Deno comes with several built-in security features that make it a compelling choice for developers concerned about application security. This guide will explore some of the key security features of Deno and how they can help you build trustworthy applications. Deno’s "Secure by Default" Features Deno achieves "Secure by Default" through several key design choices and built-in features: No file, network, or environment access by default: Unlike Node.js, which grants access to the file system, network, and environment variables by default, Deno restricts these permissions unless explicitly granted. This reduces the attack surface of applications running in Deno.Explicit permissions: Deno requires explicit permissions for accessing files, networks, and other resources, which are granted through command-line flags or configuration files. This helps developers understand and control the permissions their applications have.Built-in security features: Deno includes several built-in security features, such as a secure runtime environment (using V8 and Rust), automatic updates, and a dependency inspector to identify potentially unsafe dependencies.Secure standard library: Deno provides a secure standard library for common tasks, such as file I/O, networking, and cryptography, which is designed with security best practices in mind.Sandboxed execution: Deno uses V8's built-in sandboxing features to isolate the execution of JavaScript and TypeScript code, preventing it from accessing sensitive resources or interfering with other applications.No access to critical system resources: Deno does not have access to critical system resources, such as the registry (Windows) or keychain (macOS), further reducing the risk of security vulnerabilities. Overall, Deno's "Secure by Default" approach aims to provide developers with a safer environment for building applications, helping to mitigate common security risks associated with JavaScript and TypeScript development. Comparison of “Secure by Default” With Node.js Deno takes a more proactive approach to security by restricting access to resources by default and requiring explicit permissions for access. It also includes built-in security features and a secure standard library, making it more secure by default compared to Node.js. Feature Deno Node.js File accessDenied by default, requires explicit permissionAllowed by defaultNetwork accessDenied by default, requires explicit permissionAllowed by defaultEnvironment accessDenied by default, requires explicit permissionAllowed by defaultPermissions systemUses command-line flags or configuration filesRequires setting environment variablesBuilt-in securityIncludes built-in security featuresLacks comprehensive built-in securityStandard librarySecure standard libraryStandard library with potential vulnerabilitiesSandboxed executionUses V8's sandboxing featuresLacks built-in sandboxing featuresAccess to resourcesRestricted access to critical system resourcesMay have access to critical system resources Permission Model Deno's permission model is central to its "Secure by Default" approach. Here's how it works: No implicit permissions: In Deno, access to resources like the file system, network, and environment variables is denied by default. This means that even if a script tries to access these resources, it will be blocked unless the user explicitly grants permission.Explicit permission requests: When a Deno script attempts to access a resource that requires permission, such as reading a file or making a network request, Deno will throw an error indicating that permission is required. The script must then be run again with the appropriate command-line flag (--allow-read, --allow-net, etc.) to grant the necessary permission.Fine-grained permissions: Deno's permission system is designed to be fine-grained, allowing developers to grant specific permissions for different operations. For example, a script might be granted permission to read files but not write them, or to access a specific network address but not others.Scoped permissions: Permissions in Deno are scoped to the script's URL. This means that if a script is granted permission to access a resource, it can only access that specific resource and not others. This helps prevent scripts from accessing resources they shouldn't have access to.Permissions prompt: When a script requests permission for the first time, Deno will prompt the user to grant or deny permission. This helps ensure that the user is aware of the permissions being requested and can make an informed decision about whether to grant them. Overall, Deno's permission model is designed to give developers fine-grained control over the resources their scripts can access, while also ensuring that access is only granted when explicitly requested and authorized by the user. This helps prevent unauthorized access to sensitive resources and contributes to Deno's "Secure by Default" approach. Sandboxing Sandboxing in Deno helps achieve "secure by default" by isolating the execution of JavaScript and TypeScript code within a restricted environment. This isolation prevents code from accessing sensitive resources or interfering with other applications, enhancing the security of the runtime. Here's how sandboxing helps in Deno: Isolation: Sandboxing in Deno uses V8's built-in sandboxing features to create a secure environment for executing code. This isolation ensures that code running in Deno cannot access resources outside of its sandbox, such as the file system or network, without explicit permission.Prevention of malicious behavior: By isolating code in a sandbox, Deno can prevent malicious code from causing harm to the system or other applications. Even if a piece of code is compromised, it is limited in its ability to access sensitive resources or perform malicious actions.Enhanced security: Sandboxing helps enhance the overall security of Deno by reducing the attack surface available to potential attackers. It adds an additional layer of protection against common security vulnerabilities, such as arbitrary code execution or privilege escalation.Controlled access to resources: Sandboxing allows Deno to control access to resources by requiring explicit permissions for certain actions. This helps ensure that applications only access resources they are authorized to access, reducing the risk of unauthorized access. Overall, sandboxing plays a crucial role in Deno's "secure by default" approach by providing a secure environment for executing code and preventing malicious behavior. It helps enhance the security of applications running in Deno by limiting their access to resources and reducing the impact of potential security vulnerabilities. Secure Runtime APIs Deno's secure runtime APIs provide a robust foundation for building secure applications by default. With features such as sandboxed execution, explicit permission requests, and controlled access to critical resources, Deno ensures that applications run in a secure environment. Sandboxed execution isolates code, preventing it from accessing sensitive resources or interfering with other applications. Deno's permission model requires explicit permission requests for accessing resources like the file system, network, and environment variables, reducing the risk of unintended or malicious access. Additionally, Deno's secure runtime APIs do not have access to critical system resources, further enhancing security. Overall, Deno's secure runtime APIs help developers build secure applications from the ground up, making security a core part of the development process. Implement Secure Runtime APIs Implementing secure runtime APIs in Deno involves using Deno's built-in features and following best practices for secure coding. Here's how you can implement secure-by-default behavior in Deno with examples: Explicitly request permissions: Use Deno's permission model to explicitly request access to resources. For example, to read from a file, you would use the --allow-read flag: TypeScript const file = await Deno.open("example.txt"); // Read from the file... Deno.close(file.rid); Avoid insecure features: Instead of using Node.js-style child_process for executing shell commands, use Deno's Deno.run API, which is designed to be more secure: TypeScript const process = Deno.run({ cmd: ["echo", "Hello, Deno!"], }); await process.status(); Enable secure flag for import maps: When using import maps, ensure the secure flag is enabled to restrict imports to HTTPS URLs only: JSON { "imports": { "example": "https://example.com/module.ts" }, "secure": true } Use HTTPS for network requests: Always use HTTPS for network requests. Deno's fetch API supports HTTPS by default: TypeScript const response = await fetch("https://example.com/data.json"); const data = await response.json(); Update dependencies regularly: Use Deno's built-in security audits to identify and update dependencies with known vulnerabilities: Shell deno audit Enable secure runtime features: Take advantage of Deno's secure runtime features, such as automatic updates and dependency inspection, to enhance the security of your application.Implement secure coding practices: Follow secure coding practices, such as input validation and proper error handling, to minimize security risks in your code. Managing Dependencies To Reduce Security Risks To reduce security risks associated with dependencies, consider the following recommendations: Regularly update dependencies: Regularly update your dependencies to the latest versions, as newer versions often include security patches and bug fixes. Use tools like deno audit to identify and update dependencies with known vulnerabilities.Use semantic versioning: Follow semantic versioning (SemVer) for your dependencies and specify version ranges carefully in your deps.ts file to ensure that you receive bug fixes and security patches without breaking changes.Limit dependency scope: Only include dependencies that are necessary for your project's functionality. Avoid including unnecessary or unused dependencies, as they can introduce additional security risks.Use import maps: Use import maps to explicitly specify the mapping between module specifiers and URLs. This helps prevent the use of malicious or insecure dependencies by controlling which dependencies are used in your application.Check dependency health: Regularly check the health of your dependencies using tools like `deno doctor` or third-party services. Look for dependencies with known vulnerabilities or that are no longer actively maintained.Use dependency analysis tools: Use dependency analysis tools to identify and remove unused dependencies, as well as to detect and fix vulnerabilities in your dependencies.Review third-party code: When using third-party dependencies, review the source code and documentation to ensure that they meet your security standards. Consider using dependencies from reputable sources or well-known developers.Monitor for security vulnerabilities: Monitor security advisories and mailing lists for your dependencies to stay informed about potential security vulnerabilities. Consider using automated tools to monitor for vulnerabilities in your dependencies.Consider security frameworks: Consider using security frameworks and libraries that provide additional security features, such as input validation, authentication, and encryption, to enhance the security of your application.Implement secure coding practices: Follow secure coding practices to minimize security risks in your code, such as input validation, proper error handling, and using secure algorithms for cryptography. Secure Coding Best Practices Secure coding practices in Deno are similar to those in other programming languages but are adapted to Deno's unique features and security model. Here are some best practices for secure coding in Deno: Use explicit permissions: Always use explicit permissions when accessing resources like the file system, network, or environment variables. Use the --allow-read, --allow-write, --allow-net, and other flags to grant permissions only when necessary.Avoid using unsafe APIs: Deno provides secure alternatives to some Node.js APIs that are considered unsafe, such as the child_process module. Use Deno's secure APIs instead.Sanitize input: Always sanitize user input to prevent attacks like SQL injection, XSS, and command injection. Use libraries like std/encoding/html to encode HTML entities and prevent XSS attacks.Use HTTPS: Always use HTTPS for network communication to ensure data integrity and confidentiality. Deno's fetch API supports HTTPS by default.Validate dependencies: Regularly audit and update your dependencies to ensure they are secure. Use Deno's built-in audit tools to identify and mitigate vulnerabilities in your dependencies.Use secure standard library: Deno's standard library (std) provides secure implementations of common functionality. Use these modules instead of relying on third-party libraries with potential vulnerabilities.Avoid eval: Avoid using eval or similar functions, as they can introduce security vulnerabilities by executing arbitrary code. Use alternative approaches, such as functions and modules, to achieve the desired functionality.Minimize dependencies: Minimize the number of dependencies in your project to reduce the attack surface. Only include dependencies that are necessary for your application's functionality.Regularly update Deno: Keep Deno up to date with the latest security patches and updates to mitigate potential vulnerabilities in the runtime.Enable secure flags: When using import maps, enable the secure flag to restrict imports to HTTPS URLs only, preventing potential security risks associated with HTTP imports. Conclusion Deno's design philosophy, which emphasizes security and simplicity, makes it an ideal choice for developers looking to build secure applications. Deno's permission model and sandboxing features ensure that applications have access only to the resources they need, reducing the risk of unauthorized access and data breaches. Additionally, Deno's secure runtime APIs provide developers with tools to implement encryption, authentication, and other security measures effectively. By leveraging Deno's security features, developers can build applications that are not only secure but also reliable and trustworthy. Deno's emphasis on security from the ground up helps developers mitigate common security risks and build applications that users can trust. As we continue to rely more on digital technologies, the importance of building trustworthy applications cannot be overstated, and Deno provides developers with the tools they need to meet this challenge head-on.

By Josephine Eskaline Joyce DZone Core CORE

Top Open Source Experts

expert thumbnail

Mark Gardner

Certified full-stack web developer and back-end software engineer with 16+ years of Perl experience. Proficient in multiple programming languages, databases, DevOps, and CI/CD. Passionate about collaborative problem-solving and quickly realizing impactful results from grasping new technologies.
expert thumbnail

Nuwan Dias

VP and Deputy CTO,
WSO2

expert thumbnail

Radivoje Ostojic

Principal Software Engineer,
BrightMarbles

expert thumbnail

Adam Houghton

Senior Software Developer,
SAS Institute

The Latest Open Source Topics

article thumbnail
Automatic Code Transformation With OpenRewrite
Learn how OpenRewrite enhances automated refactoring, improves code quality, and tackles maintenance challenges with real-world examples and benefits.
May 9, 2025
by Gangadhararamachary Ramadugu
· 2,853 Views · 1 Like
article thumbnail
Mastering Fluent Bit: Installing Fluent Bit From Source (Part 1)
This intro to mastering Fluent Bit covers what Fluent Bit is, why source installs matter, and how to get it running locally in minutes.
April 17, 2025
by Eric D. Schabell DZone Core CORE
· 6,486 Views · 2 Likes
article thumbnail
Introducing Neuron AI: Create Full-Featured AI Agents in PHP
A complete open-source toolkit for AI development in PHP. Create RAG systems to use the powerful capabilities of LLMs on your own private data.
April 14, 2025
by Valerio Barbera
· 2,468 Views · 2 Likes
article thumbnail
Maintaining ML Model Accuracy With Automated Drift Detection
This tutorial demonstrates how to implement automated drift detection, triggers alerts, and automatically retrains models to maintain accuracy in production environments.
April 2, 2025
by Jesse Williams
· 2,139 Views · 2 Likes
article thumbnail
Cost-Aware Resilience: Implementing Chaos Engineering Without Breaking the Budget
See how to apply cost-aware chaos engineering techniques using open-source tools, automation, and prioritization to improve system resilience without breaking the bank.
April 1, 2025
by Binoj Melath Nalinakshan Nair DZone Core CORE
· 6,153 Views · 6 Likes
article thumbnail
GenAI: Running Prototypes Faster Than Wireframes
GenAI creates working software — faster than wireframes. Enter a prompt, you get a database, app, and API. With declarative business logic. Customize in your IDE.
March 12, 2025
by Val Huber DZone Core CORE
· 3,328 Views · 4 Likes
article thumbnail
Build Your Tech Startup: 4 Key Traps and Ways to Tackle Them
Overcontrol, poor management, no future investment, and weak tech branding can sink your project. Avoid these traps when building your own startup.
March 11, 2025
by Filipp Shcherbanich DZone Core CORE
· 3,357 Views · 4 Likes
article thumbnail
Vendor Lock-In Drives Open-Source Adoption in Japan
Open-source software is gaining ground in Japanese corporate strategy, driven by AI, cloud-native adoption, and expanded use in the manufacturing industry.
March 10, 2025
by Jesse Casman DZone Core CORE
· 2,349 Views · 1 Like
article thumbnail
How to Quarantine a Malicious File in Java
Quarantining malicious files has advantages over outright deleting. With the right tools, we can store malicious content in an isolated directory.
February 24, 2025
by Brian O'Neill DZone Core CORE
· 5,771 Views · 3 Likes
article thumbnail
Kata Containers: From Kubernetes Pods to Secure VMs
Kata containers bridge the gap between Kubernetes pods and secure VMs, offering enhanced isolation without sacrificing performance.
February 20, 2025
by Anilkumar Mallakkanavar
· 6,095 Views · 1 Like
article thumbnail
How Open Source Can Elevate Your Career as a Software Engineer
Open source helps engineers advance their careers by mastering architecture, design, documentation, testing, data persistence, and leadership—key skills for staff and principal roles.
February 20, 2025
by Otavio Santana DZone Core CORE
· 4,094 Views · 6 Likes
article thumbnail
Why and How to Participate in Open-Source Projects in 2025
Contribute to open source in 2025 to grow your skills, expand your network, and stand out in your career. Learn, collaborate, and build real-world experience.
February 13, 2025
by Otavio Santana DZone Core CORE
· 4,698 Views · 10 Likes
article thumbnail
Community Over Code Keynotes Stress Open Source's Vital Role
This year's Community Over Code keynotes highlighted a maturing open-source ecosystem tackling new challenges around security, regulation, and scalability.
February 6, 2025
by Brian Proffitt
· 3,056 Views · 5 Likes
article thumbnail
How to Add Comments in Terraform Code
The types of comments in Terraform, how to use them effectively, and best practices for writing clear, concise annotations.
February 6, 2025
by Mariusz Michalowski
· 3,908 Views
article thumbnail
90% Cost Reduction With Prefix Caching for LLMs
Up to 70% of prompts in LLM applications are repetitive. Prefix caching can reduce inference costs by up to 90%, thus optimizing performance and saving money.
February 3, 2025
by Mahak Shah
· 2,337 Views
article thumbnail
Seamless Transition from Elasticsearch to OpenSearch
A step-by-step guide for migrating from Elasticsearch to OpenSearch, ensuring compatibility, performance, and cost-efficiency.
January 20, 2025
by Nilesh Jain
· 4,586 Views · 3 Likes
article thumbnail
Talk to Your Project: An LLM Experiment You Can Join and Build On
Find out the result of my experiment on integrating LLM into a console application and the insights I gained from the experience.
January 17, 2025
by Filipp Shcherbanich DZone Core CORE
· 2,687 Views · 2 Likes
article thumbnail
Router4j: A Free Alternative to Google Maps for Route and Distance Calculation
Router4j is a free and open-source tool for calculating routes and straight-line distances based on geographic coordinates — a free alternative to Google Maps.
January 14, 2025
by Thiago Nascimento DZone Core CORE
· 4,509 Views · 5 Likes
article thumbnail
Buildpacks: An Open-Source Alternative to Chainguard
As the industry's need for secure container images is jumping, an OSS Docker alternative provides a solid foundation to solve that issue.
January 13, 2025
by Sylvain Kalache
· 8,597 Views · 3 Likes
article thumbnail
From Prompt to Running Microservice: ServiceBricks Step-By-Step
Using ServiceBricks and this step-by-step guide, create modular microservices from scratch with artificial intelligence, source code generation, and a prompt.
December 24, 2024
by Danny Logsdon
· 5,364 Views · 4 Likes
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • ...
  • Next

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: