from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return "Hello, Flask!"
@app.route()
decorator. The @app.route()
decorator takes a URL as the argument and a function as the value. The function that you pass to the @app.route()
decorator will be called when the URL is requested.@app.route('/user/<username>') def show_user(username): return f"Hello, {username}!"
redirect()
function to redirect to another URL.
from flask import redirect @app.route('/old-url') def old_url(): return redirect('/new-url')
@app.errorhandler()
decorator. The @app.errorhandler()
decorator takes an error code as the argument and a function as the value. The function that you pass to the @app.errorhandler()
decorator will be called when the error code is encountered.In Flask, you can handle errors using error handlers and exception handling. Flask provides ways to customize error pages for different HTTP status codes and also allows you to handle exceptions that might occur during the execution of your application. Let’s look at both methods:Error Handlers: Flask allows you to create custom error handlers for specific HTTP status codes. You can use the @app.errorhandler
decorator to define error handlers for various status codes.
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def index(): return "Hello, Flask!" # Custom error handler for 404 Not Found @app.errorhandler(404) def page_not_found(error): return render_template('404.html'), 404 # Custom error handler for 500 Internal Server Error @app.errorhandler(500) def internal_server_error(error): return "Internal Server Error", 500 if __name__ == '__main__': app.run(debug=True)
Exception handling in Flask allows you to catch and handle exceptions that occur during the execution of your application. You can use the try
, except
, and finally
blocks to handle exceptions and respond accordingly.
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def index(): return "Hello, Flask!" @app.route('/divide/<int:num>') def divide_by_zero(num): try: result = 10 / num return f"The result is: {result}" except ZeroDivisionError: return "Error: Cannot divide by zero." except Exception as e: return f"An error occurred: {str(e)}" if __name__ == '__main__': app.run(debug=True)
from flask_wtf import FlaskForm from wtforms import StringField, SubmitField class MyForm(FlaskForm): name = StringField('Name') submit = SubmitField('Submit')
from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mydatabase.db' db = SQLAlchemy(app)
class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) def __repr__(self): return f'<User {self.username}>'
from flask import Flask from flask_restful import Resource, Api app = Flask(__name__) api = Api(app) class HelloWorld(Resource): def get(self): return {'message': 'Hello, World!'} api.add_resource(HelloWorld, '/') if __name__ == '__main__': app.run(debug=True)
from flask_jwt import JWT, jwt_required, current_identity from werkzeug.security import safe_str_cmp # Sample user class class User: def __init__(self, id, username, password): self.id = id self.username = username self.password = password # Dummy user data users = [ User(1, 'user1', 'password1'), User(2, 'user2', 'password2') ] # JWT authentication functions def authenticate(username, password): user = next((user for user in users if user.username == username), None) if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')): return user def identity(payload): user_id = payload['identity'] return next((user for user in users if user.id == user_id), None) app.config['SECRET_KEY'] = 'super-secret-key' jwt = JWT(app, authenticate, identity) @app.route('/protected') @jwt_required() def protected(): return f'Hello, {current_identity.username}!'
from flask_caching import Cache app = Flask(__name__) app.config['CACHE_TYPE'] = 'simple' cache = Cache(app) @app.route('/slow') @cache.cached(timeout=60) def slow_function(): # Expensive calculation or operation return "Slow response" if __name__ == '__main__': app.run(debug=True)
from flask import Flask, render_template from flask_socketio import SocketIO app = Flask(__name__) app.config['SECRET_KEY'] = 'secret_key' socketio = SocketIO(app) @app.route('/') def index(): return render_template('index.html') @socketio.on('message') def handle_message(message): print('Received message: ', message) socketio.send('Message received: ' + message) if __name__ == '__main__': socketio.run(app, debug=True)
In Flask, you can handle these HTTP requests using different route decorators (@app.route) to specify the URL patterns for each type.
In Flask, you can handle both GET and POST requests using the route decorators (@app.route) and request methods in view functions.
debug
parameter to True
when creating the Flask application:
from flask import Flask app = Flask(__name__) app.debug = True
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return "Hello, Flask!" with app.test_client() as client: response = client.get('/') print(response.data) # Output: b'Hello, Flask!'
# This is a single-line comment ''' This is a multi-line comment Line 1 Line 2 '''
my_list = [1, 2, 3] my_tuple = (4, 5, 6) my_list[0] = 10 # Valid, modifies the list # my_tuple[0] = 10 # Invalid, will raise an error
def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper @my_decorator def say_hello(): print("Hello!") say_hello()
A decorator is a function that takes another function as its input and returns a new function. The new function is a wrapper around the original function.
def debug(func): def wrapper(*args, **kwargs): print('Calling {}'.format(func.__name__)) return func(*args, **kwargs) return wrapper @debug def factorial(n): if n == 0: return 1 else: return n * factorial(n - 1) print(factorial(5))
x = [1, 2, 3] y = x print(x is y) # True print(x == y) # True z = [1, 2, 3] print(x is z) # False print(x == z) # True
lambda
keyword. They are typically used for short, simple tasks.
add = lambda x, y: x + y print(add(2, 3)) # Output: 5
squares = [x ** 2 for x in range(1, 6)] print(squares) # Output: [1, 4, 9, 16, 25]
A comprehension is a concise way to create a list, set, or dictionary. Comprehensions are often used to filter or transform a sequence of values.
even_numbers = [i for i in range(10) if i % 2 == 0] squares = {i ** 2 for i in range(10)} names_and_ages = {name: age for name, age in zip(['John', 'Jane', 'Mary'], [30, 25, 40])}
try
block contains the code that may raise an exception, and the except
block handles the exception if it occurs.
try: num = int(input("Enter a number: ")) result = 10 / num except ZeroDivisionError: print("Error: Cannot divide by zero.") except ValueError: print("Error: Invalid input. Please enter a number.") else: print("Result:", result) finally: print("Execution completed.")
yield
keyword to return an iterator, allowing you to iterate over a sequence of values without generating the entire sequence at once.
def countdown(n): while n > 0: yield n n -= 1 for i in countdown(5): print(i)
5 4 3 2 1
A generator is a function that can be used to iterate over a sequence of values. Generators are often used to create iterators, which are objects that can be used to iterate over a sequence of values.
def fibonacci(n): a, b = 0, 1 for i in range(n): yield a a, b = b, a + b for i in fibonacci(10): print(i)
__str__
and __repr__
?__str__
is used to provide a user-friendly string representation of an object, while __repr__
is used to provide a developer-friendly string representation, often used for debugging.
class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return f"{self.name}, {self.age} years old." def __repr__(self): return f"Person('{self.name}', {self.age})" person = Person("Alice", 30) print(str(person)) # Output: Alice, 30 years old. print(repr(person)) # Output: Person('Alice', 30)
if x < 0: pass # Placeholder for handling negative numbers else: print("Positive number")
class Person: def __init__(self, name, age): self.name = name self.age = age def say_hello(self): print('Hello, my name is {}'.format(self.name)) person = Person('John Doe', 30) person.say_hello()
class Animal: def __init__(self, name): self.name = name def make_sound(self): print('I am an animal!') class Dog(Animal): def __init__(self, name, breed): super().__init__(name) self.breed = breed def bark(self): print('Woof!') class Cat(Animal): def __init__(self, name, fur_color): super().__init__(name) self.fur_color = fur_color def meow(self): print('Meow!') dog = Dog('Sparky', 'Golden Retriever') dog.bark() cat = Cat('Mittens', 'Black') cat.meow()
with open("example.txt", "r") as file: data = file.read() # The file is automatically closed after exiting the 'with' block
copy
module or using the slice operator.
import copy # Shallow copy using copy module original_list = [1, 2, 3] copied_list = copy.copy(original_list) # Deep copy using copy module original_list = [1, [2, 3], 4] copied_list = copy.deepcopy(original_list) # Shallow copy using slice operator original_list = [1, 2, 3] copied_list = original_list[:]
class A: def method_a(self): print("Method A") class B: def method_b(self): print("Method B") class C(A, B): pass obj = C() obj.method_a() # Output: Method A obj.method_b() # Output: Method B
open()
to open a file and perform operations like reading, writing, or appending data.
# Writing to a file with open("data.txt", "w") as file: file.write("Hello, World!") # Reading from a file with open("data.txt", "r") as file: content = file.read() print(content) # Output: Hello, World!
def factorial(n): if n == 0: return 1 else: return n * factorial(n - 1) def test_factorial(): # Create a mock object that simulates the behavior of a real function. mock_factorial = mock.Mock() mock_factorial.return_value = 120 # Use the mock object to test the factorial function. assert factorial(5) == mock_factorial.call_count # Create a stub object that provides canned responses to requests. stub_factorial = stub.Stub() stub_factorial.return_value = 120 # Use the stub object to test the factorial function. assert factorial(5) == stub_factorial.return_value
unittest
and pytest
:
unittest
uses a more verbose syntax than pytest
. For example, unittest
requires you to explicitly define a class for each test case, while pytest
allows you to define test cases directly in functions.unittest
does not have a built-in fixture system, while pytest
does. Fixtures are reusable bits of code that can be used to set up or tear down your tests.unittest
and pytest
both have assertion libraries, but pytest
‘s assertions are more concise and expressive. For example, unittest
requires you to use the assertEqual()
method to compare two values, while pytest
allows you to use the more expressive assert
statement.pytest
has a plugin system that allows you to extend its functionality. There are many plugins available for pytest
, including plugins for generating test reports, collecting code coverage data, and running tests in parallel.In general, pytest
is a more modern and expressive testing framework than unittest
. However, unittest
is still a widely used testing framework, and it may be a better choice for some projects.
A CI server is a tool that automates the process of continuous integration. A CD server is a tool that automates the process of continuous delivery.
Here is an example of how a CI server and a CD server can be used together:
Microservice architecture is more scalable and flexible than monolithic architecture. However, it can be more complex to develop and maintain.
Here is an example of how a microservice architecture and a monolithic architecture can be used:
RESTful APIs are more lightweight and easier to use than SOAP APIs. However, SOAP APIs can be more powerful and can support more complex data types.
Here is an example of how a RESTful API and a SOAP API can be used:
JSON APIs are more lightweight and easier to use than XML APIs. However, XML APIs can be more powerful and can support more complex data types.
Here is an example of how a JSON API and an XML API can be used:
from flask import Flask app = Flask(__name__) @app.route('/users', methods=['GET']) def get_users(): """Get a list of all users.""" users = [ {'id': 1, 'name': 'John Doe'}, {'id': 2, 'name': 'Jane Doe'}, ] return jsonify(users) @app.route('/users/<int:user_id>', methods=['GET']) def get_user(user_id): """Get a specific user by ID.""" user = {'id': user_id, 'name': 'John Doe'} return jsonify(user) if __name__ == '__main__': app.run(debug=True)
This code defines two RESTful APIs:
/users
: This API returns a list of all users./users/<int:user_id>
: This API returns a specific user by ID.The GET
method is used to retrieve data from the API, the POST
method is used to create new data, the PUT
method is used to update existing data, and the DELETE
method is used to delete data.
The data returned by the API is in JSON format. JSON is a lightweight data-interchange format that is easy to read and write.
query { user(id: 1) { name age } }
A RESTful API might use the following HTTP requests to fetch the same data:
GET /users/1 GET /users/1/name GET /users/1/age
In general, GraphQL APIs are a good choice for applications where the data is the most important part of the API. RESTful APIs are a good choice for applications where the resources are the most important part of the API.
Here is a table that summarizes the key differences between GraphQL APIs and RESTful APIs:
Feature | GraphQL API | RESTful API |
---|---|---|
Querying | Single query language | Different verbs for different types of requests |
Data fetching | Clients specify exactly the data that they need | Clients fetch all of the data for a resource |
Data modeling | Data-driven | Resource-driven |
Complexity | More complex to develop | Less complex to develop |
Best for | Applications where the data is the most important part of the API | Applications where the resources are the most important part of the API |
In a standard application without dependency injection, components and services often create or look up their dependencies. This creates tight coupling between components and makes them harder to test or reuse. With DI, components declare their dependencies (typically via constructor arguments, properties, or annotations), and a container or framework (like Spring) provides those dependencies. This helps in:
@Service public class OrderService { private final UserRepository userRepository; @Autowired public OrderService(UserRepository userRepository) { this.userRepository = userRepository; } // Other methods }
Note: In modern Spring versions, if a class has a single constructor, the @Autowired
annotation can be omitted, and Spring will use that constructor by default.
@Service public class OrderService { private UserRepository userRepository; @Autowired public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } // Other methods }
@Service public class OrderService { @Autowired private UserRepository userRepository; // Other methods }
@Qualifier
annotation.
@Service public class OrderService { private final DataSource dataSource; @Autowired public OrderService(@Qualifier("mainDataSource") DataSource dataSource) { this.dataSource = dataSource; } // Other methods }
Car
) object that creates its own engine (Engine
) instance.
public class Engine { public void start() { // Start engine } } public class Car { private Engine engine; public Car() { this.engine = new Engine(); } }
In the example above, the Car
class is tightly coupled to a specific Engine
. This makes it challenging to replace Engine
with a different implementation or to mock the engine during testing.
public class Car { private Engine engine; public Car(Engine engine) { this.engine = engine; } }
Here, the Car
doesn’t create its Engine
. Instead, it’s supplied with an engine. This makes it possible to provide different engine implementations or mock engines for testing.
<!-- Spring XML Configuration --> <bean id="engine" class="com.example.Engine" /> <bean id="car" class="com.example.Car"> <constructor-arg ref="engine"/> </bean>
@Component public class Engine { @PostConstruct public void initialize() { // Initialization code } @PreDestroy public void cleanup() { // Cleanup code } }
In essence, IoC flips the traditional flow of control. Instead of objects controlling their own dependencies, a container or framework takes on the responsibility. This inversion leads to software that’s more modular, easier to test, and more resilient to change.
Here, the initialize
method is called after the Engine
bean is created, and cleanup
is called before it’s destroyed.
The IoC container receives metadata from XML files, annotations, or Java configuration classes, and then uses this metadata to create and manage the lifecycle of the beans. The main tasks of the IoC container are:
There are two primary types of IoC containers in Spring:
BeanFactory
. It provides additional features such as event propagation, declarative mechanisms to create a bean, integration with AOP (Aspect-Oriented Programming), and more. In most Spring-based applications (including Spring Boot apps), ApplicationContext
is used more often than BeanFactory
.Spring Boot simplifies the use of the IoC container by eliminating most of the boilerplate configuration. With features like auto-configuration and component scanning, Spring Boot makes it easier to create, wire, and manage beans with minimal explicit configuration.
@Component public class HelloWorld { public String sayHello() { return "Hello, World!"; } }
@Service public class MessageService { private final HelloWorld helloWorld; @Autowired public MessageService(HelloWorld helloWorld) { this.helloWorld = helloWorld; } public void showMessage() { System.out.println(helloWorld.sayHello()); } }
@SpringBootApplication public class MyApp { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(MyApp.class, args); MessageService messageService = context.getBean(MessageService.class); messageService.showMessage(); } }
@SpringBootApplication
annotation?@Configuration
, @EnableAutoConfiguration
, and @ComponentScan
.banner.txt
file in the src/main/resources
directory or setting a banner.location
property.@Value
annotation or by injecting the Environment
object.application.properties
and application.yml
:
src/main/resources
).application-dev.properties
for a dev
profile).application.properties
application.properties
or application.yml
in the jar (lowest precedence).SPRING_DATASOURCE_URL
would map to the spring.datasource.url
property in the application.@Value
Annotation:
@Value("${property.name}")
annotation.
@Value("${custom.property}") private String customProperty;
@Value
annotation, you can bind properties to POJOs annotated with @ConfigurationProperties
. This method is type-safe and offers additional benefits like validation and code-completion in IDEs.
@ConfigurationProperties(prefix="custom") public class CustomProperties { private String property; // getters and setters }
${another.property}
).spring.datasource.url
, spring.datasource-url
, SPRING_DATASOURCE_URL
, and spring.datasource_url
would all match the spring.datasource.url
property.spring.profiles.active
property (e.g., in application.properties
or as a command-line argument).SPRING_PROFILES_ACTIVE
environment variable.SpringApplication.setAdditionalProfiles(...)
method programmatically.application-dev.properties
will only be applied when the dev
profile is active.application-dev.yml
.@Profile
annotation:
@Profile("dev") @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder().build(); }
cloud
profile that’s used for any cloud provider and a aws
profile that’s specific to AWS. You can activate both profiles simultaneously.default
profile will be used.@Profile("!prod") @Bean public DataSource dataSource() { // This bean will be created when the 'prod' profile is NOT active }
java -jar myapp.jar --spring.profiles.active=prod
spring.profiles.active
property./health
, /info
, /metrics
, /env
.@EntityScan
?SpringApplication.run()
method.server.*
properties (e.g., server.port
).@RepositoryRestResource
?spring-boot-starter-aop
.application.properties
or application.yml
.@RestController
vs @Controller
.@RestController
is a shorthand for @Controller
+ @ResponseBody
.@EnableTransactionManagement
and by using @Transactional
on methods.@ControllerAdvice
and @ExceptionHandler
.spring-boot-starter-test
with utilities like MockMvc
.spring-boot-maven-plugin
.@ComponentScan(excludeFilters = @Filter)
.application.properties
?spring.config.location
property.server.port
in application.properties
.@Conditional
It indicates a component is only eligible for registration when a specific condition matches.@SpringBootTest
?SpringApplication
and loads all registered beans.@SpringBootTest
is an annotation provided by Spring Boot that is used for integration testing. It helps to bootstrap the entire container (depending on the provided configuration), so you can test the application in scenarios close to the actual use.Features of @SpringBootTest
:
Examples of using @SpringBootTest
:
@SpringBootTest class MyApplicationTests { @Test void contextLoads() { } }
This test ensures that the application context loads without any issues.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class MyWebApplicationTests { @Autowired TestRestTemplate restTemplate; @Test void testHomeEndpoint() { String response = restTemplate.getForObject("/", String.class); assertEquals("Hello World", response); } }
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) class MyWebMockTest { @Autowired MockMvc mockMvc; @Test void testEndpoint() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/")) .andExpect(status().isOk()) .andExpect(content().string("Hello World")); } }
@SpringBootTest(properties = {"custom.property=value"}) class PropertyOverrideTest { //... }
@ActiveProfiles
: To activate certain profiles during testing, you can combine it with @ActiveProfiles
:
@SpringBootTest @ActiveProfiles("test") class MyProfileTest { //... }
The @SpringBootTest
annotation simplifies integration testing for Spring Boot applications by setting up and tearing down the application context and providing various utilities and configurations specific to the testing phase.
35. How can you serve static content in Spring Boot?
/public
, /resources
, /static
, or /META-INF/resources
directories.By default, Spring Boot serves static content from the following locations inside your project:
/META-INF/resources/
/resources/
/static/
/public/
For instance, if you place an index.html
file inside the src/main/resources/static/
directory of your Spring Boot application, you can access it by visiting http://localhost:8080/index.html
after starting your application.
If you want to customize the static content locations, you can do so by configuring the spring.resources.static-locations
property. For example, to serve static content from a custom-dir
directory:
spring.resources.static-locations=classpath:/custom-dir/
36. Describe the hierarchy of application.properties
in Spring Boot.
@TestPropertySource
, @SpringBootTest.properties
, and inside the JAR are examples of levels.
In Spring Boot, the application.properties
(or its YAML counterpart, application.yml
) file is the primary means for configuring application settings. Spring Boot provides a flexible system of looking for this configuration file in various locations and offers a hierarchy that determines the order of precedence for reading these configurations.
Here’s the hierarchy for application.properties
locations, starting from the highest precedence:
java -jar app.jar --server.port=8081
SPRING_APPLICATION_JSON
:
SPRING_APPLICATION_JSON
environment variable.-D
argument, e.g., java -Dserver.port=8081 -jar app.jar
server.port
can be sourced from an environment variable named SERVER_PORT
.application.properties
or application.yml
located in the same directory from which the application is run../config
sub-directory of the directory from which the application is run.application.properties
or application.yml
at the root of the classpath, typically inside the src/main/resources
directory./config
package or directory inside the jar.application.properties
or application.yml
located in the classpath root.SpringApplication.setDefaultProperties
.Profile-specific properties:
Along with the above, Spring Boot allows for profile-specific property files. These are named like application-{profile}.properties
or application-{profile}.yml
. Profile-specific property files have precedence over the default application.properties
or application.yml
but are ordered by the same precedence rules mentioned above.
For example, if a dev
profile is active, application-dev.properties
outside the jar will override the application.properties
outside the jar, but both will be overridden by any value passed as a command-line argument.
Conclusion: The hierarchy and the ability to source configurations from various locations allow for a high degree of flexibility. You can have default settings packaged within your application and override them for different environments using external files or even command-line arguments. This makes it easier to manage configurations across different deployment scenarios without changing the packaged application.
37. What is a Spring Boot Fat JAR?
38. What are the main advantages of using Spring Boot?
39. How do you enable debug logging in Spring Boot?
logging.level.root=DEBUG
in application.properties
.40. Explain the importance of the pom.xml
file in Spring Boot.
41. What’s the purpose of @EnableAutoConfiguration
?
42. How does Spring Boot simplify database connectivity?
spring-boot-starter-data-jpa
.application.properties
or application.yml
files.spring.datasource.url
, spring.datasource.username
, and spring.datasource.password
, you can configure a data source without any manual bean definitions.
spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=secret
spring.datasource.hikari.maximum-pool-size=10
EntityManager
.CrudRepository
or JpaRepository
and Spring Boot automatically provides the implementation at runtime, enabling CRUD operations on entities without writing the boilerplate code.schema.sql
and data.sql
) and run them at startup to initialize the database.schema.sql
in the src/main/resources
directory, Spring Boot will execute it on startup.schema.sql
:application-{profile}.properties
files can be used for different environments. This means you can have separate configurations for development, staging, and production, making it easy to switch between databases based on the active profile.JdbcTemplate
, making it easier to interact with relational databases without managing connections and exceptions manually.
@Autowired JdbcTemplate jdbcTemplate; public int getCountOfBooks() { return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM book", Integer.class); }
DataAccessException
, making it easier to handle database-related errors in a consistent way.In essence, Spring Boot removes much of the boilerplate code traditionally associated with setting up and managing database connections in a Spring application. This allows developers to focus on their domain logic rather than the intricacies of database setup and connectivity.43. What is the importance of @Repository
in Spring Boot?
44. How can you specify the active profile while running a Spring Boot application?
--spring.profiles.active=myprofile
during startup.45. How can you secure a Spring Boot application?
spring-boot-starter-security
and @EnableWebSecurity
.First and foremost, you’ll need to add the Spring Security starter to your pom.xml
(if using Maven):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
By merely including the above dependency, Spring Boot will set up basic authentication for all routes with a default user named “user” and a generated password that’s displayed in the console on startup.
Example: Accessing any endpoint without authentication will return a 401 Unauthorized
. Use the provided username and password in the request header or when prompted by the browser to authenticate.
You can configure user details and their roles in memory or retrieve them from a database.
Example – In-memory Authentication:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password("{noop}admin123").roles("ADMIN") .and() .withUser("user").password("{noop}user123").roles("USER"); } }
You can specify which routes or endpoints are accessible by which roles.
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("ADMIN", "USER") .antMatchers("/").permitAll() .and().formLogin(); }
46. What is a CommandLineRunner
in Spring Boot?
47. Describe the structure of a typical Spring Boot project.
src/main/java
and resources in src/main/resources
.48. How can you customize the Jackson ObjectMapper in Spring Boot?
@Bean
of type ObjectMapper
in a configuration class.49. What are the benefits of using the Spring Boot DevTools?
50. What is spring-boot-starter-parent
?
What is Flask?
Flask is a web development framework. It provides a lot libraries for building lightweight web applications in python. Flask is considered by many as a micro-framework due to the fact that it only provides the essential components – things like routing, request handling, sessions, and so on. It provides you with libraries, tools, and modules to develop web applications like a blog, wiki, or even a commercial website. It’s considered “beginner friendly” because it doesn’t have boilerplate code or dependencies which can distract from the primary function of an application. Data handling handling for example, the developer can write a custom module or use an extension.
What is Flask used for?
Flask is mainly used for backend development, but it makes use of a templating language called Jinja2 which is used to create HTML, XML or other markup formats that are returned to the user via an HTTP request.
Note that in this series of tutorial, we’ll be using Flask as a backend framework and React as a frontend framework.